zoukankan      html  css  js  c++  java
  • [CTSC2008]网络管理Network

    ## [ 传送门 ](https://www.lydsy.com/JudgeOnline/problem.php?id=1146)

    Descroption

    带修改求树上路径第k大

    Solution

    方法一:树状数组套主席树

    出题人总是比较喜欢把序列的东西搬到树上去

    但这并不影响我们做题,因为我们可以用一个log的时间将它变回序列的操作(树链剖分)

    使用树状数组,是因为它可以支持单点加和区间求和的操作。

    我们求出dfs序,然后按照顺序,将每个点离散后的权值,加到树状数组上去

    其实是加到树状数组每个点所对应的权值线段树上

    这样,我们处理操作的时候:

    • 修改操作:就和之前的加点一样,在原权值处-1,新权值处+1
    • 询问操作:找出x和y到它们的lca上的log条重链,每条链都对应dfs序的一个区间,我们先记录下这log个区间,然后在权值线段树上二分,对这些区间的端点加加减减一下,就能求出相应权值区间的数量啦

    复杂度是(O(n log^3 n))

    之前求成第k小了,wa了无数次,我真菜


    Code 

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    #define reg register
    #define MN 80005
    int n,m,val[MN],s[MN<<1],tot;
    struct OPT{int l,r,k;}o[MN];
    int ls[MN*200],rs[MN*200],t[MN*200],sz,rt[MN];
    #define mid ((l+r)>>1)
    void Modify(int &rt,int l,int r,int x,int v)
    {
    	++sz;ls[sz]=ls[rt];rs[sz]=rs[rt];t[sz]=t[rt]+v;rt=sz;
    	if(l==r) return;
    	if(x<=mid) Modify(ls[rt],l,mid,x,v);
    	else Modify(rs[rt],mid+1,r,x,v);
    }
    int tmp[400],cnt,sign[400];
    int Query(int l,int r,int k)
    {
    	if(l==r) return l;
    	register int sum=0,i;
    	for(i=1;i<=cnt;++i) sum+=t[rs[tmp[i]]]*sign[i];
    	if(k<=sum)
    	{
    		for(i=1;i<=cnt;++i) tmp[i]=rs[tmp[i]];
    		return Query(mid+1,r,k);
    	}
    	else
    	{
    		for(i=1;i<=cnt;++i) tmp[i]=ls[tmp[i]];
    		return Query(l,mid,k-sum);
    	}
    }
    #define lb(x) (x&(-x))
    inline void C(int x,int p,int v){for(;x<=n;x+=lb(x)) Modify(rt[x],1,tot,p,v);}
    struct edge{int to,nex;}e[MN<<1];int hr[MN],en;
    inline void ins(int f,int t)
    {
        e[++en]=(edge){t,hr[f]};hr[f]=en;
        e[++en]=(edge){f,hr[t]};hr[t]=en;
    }
    int dfn[MN],fdfn[MN],mx[MN],top[MN],siz[MN],fa[MN],dep[MN],dind;
    void dfs1(int x,int f)
    {
        dep[x]=dep[fa[x]=f]+1;siz[x]=1;
        for(reg int i=hr[x];i;i=e[i].nex) if(f^e[i].to)
            dfs1(e[i].to,x),siz[e[i].to]>siz[mx[x]]?mx[x]=e[i].to:0,siz[x]+=siz[e[i].to];
    }
    void dfs2(int x,int tp)
    {
        dfn[x]=++dind;fdfn[dind]=x;top[x]=tp;if(mx[x]) dfs2(mx[x],tp);
        for(reg int i=hr[x];i;i=e[i].nex) if((fa[x]^e[i].to)&&(mx[x]^e[i].to))
            dfs2(e[i].to,e[i].to);
    }
    inline void Insert(int l,int r)
    {
        for(;r;r-=lb(r)) tmp[++cnt]=rt[r],sign[cnt]=1;
    	for(--l;l;l-=lb(l)) tmp[++cnt]=rt[l],sign[cnt]=-1;
    }
    inline void que(int x,int y,int k)
    {
        cnt=0;int num=1+dep[x]+dep[y];
        while(top[x]^top[y])
        {
            if(dep[top[x]]>dep[top[y]]) Insert(dfn[top[x]],dfn[x]),x=fa[top[x]];
            else Insert(dfn[top[y]],dfn[y]),y=fa[top[y]];
        }
        if(dep[x]<dep[y]) std::swap(x,y);
        Insert(dfn[y],dfn[x]);num-=2*dep[y];
    	if(num<k) puts("invalid request!");
        else printf("%d
    ",s[Query(1,tot,k)]);
    }
    int main()
    {
        n=read();m=read();
        register int i,x;
        for(i=1;i<=n;++i) ++tot,s[tot]=val[i]=read();
        for(i=1;i<n;++i) x=read(),ins(x,read());
        for(i=1;i<=m;++i)
        {
            o[i].k=read();o[i].l=read(),o[i].r=read();
            if(!o[i].k) ++tot,s[tot]=o[i].r;
        }
        std::sort(s+1,s+tot+1);
        tot=std::unique(s+1,s+tot+1)-s-1;
        for(i=1;i<=n;++i) val[i]=std::lower_bound(s+1,s+tot+1,val[i])-s;
        for(i=1;i<=m;++i) if(!o[i].k) o[i].r=std::lower_bound(s+1,s+tot+1,o[i].r)-s;
        dfs1(1,0);dfs2(1,1);
        for(i=1;i<=n;++i) C(i,val[fdfn[i]],1);
        for(i=1;i<=m;++i)
        {
            if(!o[i].k) C(dfn[o[i].l],val[o[i].l],-1),C(dfn[o[i].l],o[i].r,1),val[o[i].l]=o[i].r;
            else que(o[i].l,o[i].r,o[i].k);
        }
        return 0;
    }
    


    方法二:整体二分

    仍然是树链剖分

    用上整体二分的套路

    修改操作可以看成一次加点和一次删点

    upd:大概在一周后,终于补上了整体二分的代码......

    复杂度仍然是(O(n log^3 n))

    我怎么再次打成了第k小,我是有智力问题吧(疯了)......


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 30002
    #define MM 80002
    int n,tot,ID,val[MM],Ans[MN];
    int num[MN+MM],cnt;
    struct opt{int x,y,k,id;}q[MM+(MN<<1)],p[MM+(MN<<1)];
    struct edge{int to,nex;}e[MM<<1];int hr[MM],en;
    inline void ins(int f,int t)
    {
    	e[++en]=(edge){t,hr[f]};hr[f]=en;
    	e[++en]=(edge){f,hr[t]};hr[t]=en;
    }
    int dep[MM],fa[MM],top[MM],mx[MM],sz[MM],dfn[MM],dind;
    inline void dfs1(int x=1,int f=0)
    {
    	dep[x]=dep[fa[x]=f]+(sz[x]=1);register int i;
    	for(i=hr[x];i;i=e[i].nex)if(e[i].to^f) dfs1(e[i].to,x),(sz[e[i].to]>sz[mx[x]])?mx[x]=e[i].to:0,sz[x]+=sz[e[i].to];
    }
    inline void dfs2(int x=1,int tp=1)
    {
    	dfn[x]=++dind;top[x]=tp;if(mx[x]) dfs2(mx[x],tp);register int i;
    	for(i=hr[x];i;i=e[i].nex)if((e[i].to^fa[x])&&(e[i].to^mx[x])) dfs2(e[i].to,e[i].to);
    }
    #define lb(x) (x&(-x))
    int t[MM];
    inline void C(int x,int v){for(;x<=n;x+=lb(x))t[x]+=v;}
    inline int G(int x){int r=0;for(;x;x-=lb(x))r+=t[x];return r;}
    inline int get_lca(int x,int y){
    	for(;top[x]^top[y];)if(dep[top[x]]>dep[top[y]])x=fa[top[x]];else y=fa[top[y]];
    	return dep[x]>dep[y]?y:x;
    }
    inline int get_num(int x,int y)
    {
    	int r=0;
    	for(;top[x]^top[y];)
    		dep[top[x]]>dep[top[y]]?(r+=G(dfn[x])-G(dfn[top[x]]-1),x=fa[top[x]]):(r+=G(dfn[y])-G(dfn[top[y]]-1),y=fa[top[y]]);
    	r+=G(max(dfn[x],dfn[y]))-G(min(dfn[x],dfn[y])-1);
    	return r;
    }
    void solve(int l=1,int r=cnt,int ql=1,int qr=tot)
    {
    	if(ql>qr) return;
    	register int i;
    	if(l==r)
    	{
    		for(i=ql;i<=qr;++i) if(q[i].id) Ans[q[i].id]=num[l];
    		return;
    	}
    	register int mid=(l+r+1)>>1,pl=ql,pr=qr,tmp;
    	for(i=ql;i<=qr;++i)
    	{
    		if(!q[i].id)
    		{
    			if(q[i].y>=num[mid]) p[pr--]=q[i],C(dfn[q[i].x],q[i].k);
    			else p[pl++]=q[i];
    		}
    		else
    		{
    			tmp=get_num(q[i].x,q[i].y);
    			if(tmp>=q[i].k) p[pr--]=q[i];
    			else q[i].k-=tmp,p[pl++]=q[i];
    		}
    	}
    	for(i=ql;i<=qr;++i) if(!q[i].id&&q[i].y>=num[mid]) C(dfn[q[i].x],-q[i].k);
    	for(i=ql;i<pl;++i) q[i]=p[i];
    	for(i=pl;i<=qr;++i) q[i]=p[qr-i+pl];
    	solve(l,mid-1,ql,pl-1);solve(mid,r,pr+1,qr);
    }
    int main()
    {
    	register int i,m,x,k,y;
    	n=read();m=read();
    	for(i=1;i<=n;++i) q[++tot]=(opt){i,val[i]=read(),1,0},num[++cnt]=val[i];
    	for(i=1;i<n;++i) x=read(),ins(x,read());
    	dfs1();dfs2();
    	while(m--)
    	{
    		k=read();x=read();y=read();
    		if(!k) q[++tot]=(opt){x,val[x],-1,0},q[++tot]=(opt){x,y,1,0},num[++cnt]=val[x]=y;
    		else
    		{
    			++ID;register int lca=get_lca(x,y);
    			if(dep[x]+dep[y]-2*dep[lca]+1<k) Ans[ID]=-1;
    			else q[++tot]=(opt){x,y,k,ID};
    		}
    	}
    	std::sort(num+1,num+cnt+1);
    	cnt=std::unique(num+1,num+cnt+1)-num-1;
    	solve();
    	for(i=1;i<=ID;++i) printf(Ans[i]==-1?"invalid request!
    ":"%d
    ",Ans[i]);
    	return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    C# 与 Java Rsa加密与解密互通
    PHP 读取Postgresql中的数组
    ArcGis Javascript API (V3.6)加载天地图
    Entity Framework 6.0 对枚举的支持/实体添加后会有主键反回
    ubuntu 中 ssh连接用UTF8
    Entity Framework PostgresQL CodeFirst
    Golang 字符编码
    CentOS 安装 mono
    C和C++中的不定参数
    WisDom.Net 框架设计(一) 总体框架
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10152249.html
Copyright © 2011-2022 走看看