• P3302 [SDOI2013]森林


    题目描述

    一道非常平常的主席树题,其实还是蛮经典的

    给出一个森林,满足两种操作

    • 求一条路径上的第 (k) 大值

    • 链接两个树

    强制在线

    P3302 [SDOI2013]森林

    问题解决

    看到第 (k) 小,自然而然就想到了主席树,但是要求不断连边,所以考虑 (LCT) 但是时间复杂度和代码度都不允许,区间第 (k) 小好像没什么思虑去优化,所以考虑来优化连边, (n) 颗树的连边貌似只有启发式合并了,但是这里要去思考如何维护主席树上的值,而且要满足时间复杂度

    启发式合并的时候,我们把小的合并到大的上面去,合并的时候,我们要暴力把要修改的节点的父节点来修改这个节点,然后更新对应的 (st)

    查询的时候我们有一点书上差分的感觉,因为主席树本质上和差分有点像,在树上建主席树,记录下(x,y,lca(x,y),fa(lca(x,y))) 的值,查询的时候遵循树上差分的想法,来查询就好了

    总时间复杂度是 (O(nlog^2n)),但还是要卡一下时间

    代码实现

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn=8e4+5,maxe=4*maxn;
    int lnk[maxn],son[maxe],nxt[maxe],cnt,tot;
    int T,n,m,q;
    int a[maxn],Fa[maxn],Son[maxn],hed[maxn];
    inline void add_e(int x,int y){
    	son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;
    }
    struct node{
    	int size,ls,rs;
    }t[maxn*600];
    int root[maxn];
    struct IO{
        static const int S=1<<21;
        char buf[S],*p1,*p2;int st[105],Top;
        ~IO(){clear();}
        inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
        inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
        inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
        inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='
    '||x=='r');return *this;}
        template<typename T>inline IO&operator >> (T&x){
            x=0;bool f=0;char ch=gc();
            while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
            while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
            f?x=-x:0;return *this;
        }
        inline IO&operator << (const char c){pc(c);return *this;}
        template<typename T>inline IO&operator << (T x){
            if(x<0) pc('-'),x=-x;
            do{st[++st[0]]=x%10,x/=10;}while(x);
            while(st[0]) pc('0'+st[st[0]--]);return *this;
        }
    }fin,fout;
    inline int read(){
        int x=0;char ch=' ';int f=1;
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void build(int &now,int l,int r){
    	now=++cnt;t[now].size=0;
    	if(l==r)return ;
    	int mid=(r-l>>1)+l;
    	build(t[now].ls,l,mid);
    	build(t[now].rs,mid+1,r);
    }
    void insert(int &now,int pre,int l,int r,int x){
    	now=++cnt;t[now]=t[pre];t[now].size++;
    	if(l==r)return ;
    	int mid=(r-l>>1)+l;
    	if(x<=mid)insert(t[now].ls,t[pre].ls,l,mid,x);
    	else insert(t[now].rs,t[pre].rs,mid+1,r,x);
    }
    int b[maxn],size;
    int query(int x,int y,int pre1,int pre2,int l,int r,int k){
    	if(l==r)return b[l];
    	int lsize=t[t[x].ls].size+t[t[y].ls].size-t[t[pre1].ls].size-t[t[pre2].ls].size;
    	int mid=(r-l>>1)+l;
    	if(k<=lsize)return query(t[x].ls,t[y].ls,t[pre1].ls,t[pre2].ls,l,mid,k);
    	else return query(t[x].rs,t[y].rs,t[pre1].rs,t[pre2].rs,mid+1,r,k-lsize);
    }
    inline int Hash(int x){
    	return lower_bound(b+1,b+1+size,x)-b;
    }
    int find(int x){
    	return Fa[x]==x?x:Fa[x]=find(Fa[x]);
    }
    int st[maxn][17],dep[maxn],vis[maxn];
    void dfs(int x,int father,int rt){
    	st[x][0]=father;
    	for(int k=1;k<=16;k++){
    		st[x][k]=st[st[x][k-1]][k-1];
    	}
    	Son[rt]++;dep[x]=dep[father]+1;Fa[x]=father;vis[x]=1;
    	insert(root[x],root[father],1,size,Hash(a[x]));
    	for(int j=lnk[x];j;j=nxt[j]){
    		if(son[j]==father)continue;
    		dfs(son[j],x,rt);
    	}
    }
    inline int Lca(int x,int y){
    	if(x==y)return x;
    	if(dep[x]>dep[y])swap(x,y);
    	for(int k=16;k>=0;k--){
    		if(dep[st[y][k]]>=dep[x])y=st[y][k];
    	}
    	if(x==y)return x;
    	for(int k=16;k>=0;k--)
    		if(st[x][k]!=st[y][k])x=st[x][k],y=st[y][k];
    	return st[x][0];
    }
    int main(){
    	freopen("P3302.in","r",stdin);
    	freopen("P3302.out","w",stdout);
    	T=read();T=1;
    	while(T--){
    		memset(lnk,0,sizeof lnk);
    		memset(dep,0,sizeof dep);
    		memset(vis,0,sizeof vis);
    		memset(st,0,sizeof st);
    		memset(Son,0,sizeof Son);
    		tot=0;cnt=0;n=read();m=read();q=read();
    		for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i],Fa[i]=i;
    		sort(b+1,b+1+n);
    		size=unique(b+1,b+1+n)-b-1;
    		for(int i=1;i<=m;i++){
    			int x=read(),y=read();
    			add_e(x,y);add_e(y,x);
    		}
    		build(root[0],1,size);
    		for(int i=1;i<=n;i++){
    			if(!vis[i]){dfs(i,0,i);Fa[i]=i;}
    		}
    		int lastans=0;
    		for(int i=1;i<=q;i++){
    			char ch[3];
    			int x,y,k;
    			scanf("%s",ch);
    			x=read()^lastans;
    			y=read()^lastans;
    			if(ch[0]=='Q'){
    				k=read()^lastans;
    				int lca=Lca(x,y);
    				lastans=query(root[x],root[y],root[lca],root[st[lca][0]],1,size,k);
    				printf("%d
    ",lastans);
    			}
    			else {
    				add_e(x,y);add_e(y,x);
    				int fx=find(x),fy=find(y);
    				if(son[fx]<son[fy]){
    					swap(fx,fy);swap(x,y);
    				}
    				dfs(y,x,fx);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Countly在andoid和vps集成使用,开源的统计分析sdk
    简单dp-poj-2231-Moo Volume
    Head First设计模式-观察者模式
    D3D游戏编程系列(六):自己动手编写第一人称射击游戏之第一人称视角的构建
    面试之BI-SQL--table转换[2]
    oracle表数据误删还原
    SQL Server 2008数据库创建,备份,还原图解及注意点
    SHH入门:Spring框架简介
    基于总变差模型的纹理图像中图像主结构的提取方法。
    windows程序员进阶系列:《软件调试》之堆 (一)
  • 原文地址:https://www.cnblogs.com/martian148/p/15261812.html
Copyright © 2020-2023  润新知