zoukankan      html  css  js  c++  java
  • [SDOI2013]森林

    Description

    Input
    第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
    第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
    接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

    Output
    对于每一个第一类操作,输出一个非负整数表示答案。

    Sample Input
    1
    8 4 8
    1 1 2 2 3 3 4 4
    4 7
    1 8
    2 4
    2 1
    Q 8 7 3 Q 3 5 1
    Q 10 0 0
    L 5 4
    L 3 2 L 0 7
    Q 9 2 5 Q 6 1 6

    Sample Output
    2
    2
    1
    4
    2

    HINT


    其实这题是个暴力。。。

    首先考虑没有连边操作,那么就直接令某个点为根,统计4条链的答案即可

    如果有加边操作,我们就直接按秩合并,把较小的接到较大的下面,然后将较小的树全部重构

    由于每次合并至少会使得树的大小翻倍,因此一个点重构次数不会超过(O(log n))

    至于动态求Lca?暴力更新倍增数组,当然也可以用LCT

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	if (ch==EOF)	exit(0);
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=8e4,M=1e7;
    struct S1{
    	#define ls(x) tree[x][0]
    	#define rs(x) tree[x][1]
    	#define T(x) (rs(f[x])==x)
    	int tree[N+10][2],f[N+10],stack[N+10];
    	bool rev[N+10];
    	void Add_rev(int x){
    		if (!x)	return;
    		swap(ls(x),rs(x));
    		rev[x]^=1;
    	}
    	void pushdown(int x){
    		if (!rev[x])	return;
    		Add_rev(ls(x));
    		Add_rev(rs(x));
    		rev[x]^=1;
    	}
    	bool isroot(int x){return ls(f[x])!=x&&rs(f[x])!=x;}
    	void move(int x){
    		int fa=f[x],son=tree[x][T(x)^1];
    		tree[x][T(x)^1]=fa;
    		tree[fa][T(x)]=son;
    		if (son)	f[son]=fa;
    		f[x]=f[fa];
    		if (!isroot(fa))	tree[f[x]][T(fa)]=x;
    		f[fa]=x;
    	}
    	void splay(int x){
    		int top=0; stack[++top]=x;
    		for (int i=x;!isroot(i);i=f[i])	stack[++top]=f[i];
    		for (int i=top;i;i--)	pushdown(stack[i]);
    		while (!isroot(x)){
    			if (!isroot(f[x]))	T(x)==T(f[x])?move(f[x]):move(x);
    			move(x);
    		}
    	}
    	void Access(int x){
    		int last=0;
    		while (x){
    			splay(x);
    			rs(x)=last;
    			last=x,x=f[x];
    		}
    	}
    	void make_root(int x){
    		Access(x);
    		splay(x);
    		Add_rev(x);
    	}
    	void link(int x,int y){
    		make_root(x);
    		f[x]=y;
    	}
    	int lca(int x,int y){
    		Access(x),splay(x);
    		splay(y);
    		while (f[y]){
    			y=f[y];
    			splay(y);
    		}
    		return y;
    	}
    	#undef ls
    	#undef rs
    	#undef T
    }LCT;//Link Cut Tree;
    int root[N+10];
    struct S2{
    	int ls[M+10],rs[M+10],cnt[M+10],tot;
    	void insert(int &k,int p,int l,int r,int x){
    		cnt[k=++tot]=cnt[p]+1;
    		ls[k]=ls[p],rs[k]=rs[p];
    		if (l==r)	return;
    		int mid=(l+r)>>1;
    		if (x<=mid)	insert(ls[k],ls[p],l,mid,x);
    		else	insert(rs[k],rs[p],mid+1,r,x);
    	}
    	int Query(int k,int p,int w,int v,int l,int r,int x){
    		if (l==r)	return l;
    		int mid=(l+r)>>1,res=cnt[ls[k]]+cnt[ls[p]]-cnt[ls[w]]-cnt[ls[v]];
    		if (x<=res)	return Query(ls[k],ls[p],ls[w],ls[v],l,mid,x);
    		else	return Query(rs[k],rs[p],rs[w],rs[v],mid+1,r,x-res);
    	}
    }CT;//Chairman Tree
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10];
    int size[N+10],belong[N+10],v[N+10],list[N+10],rt[N+10],f[N+10];
    int tot,Time,T;
    void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    void insert(int x,int y){join(x,y),join(y,x);}
    void dfs(int x,int fa){
    	size[belong[x]=Time]++,f[x]=fa;
    	CT.insert(root[x],root[fa],1,T,v[x]);
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p])	if (son!=fa)	dfs(son,x);
    }
    void rebuild(int x,int fa){
    	belong[x]=belong[fa],f[x]=fa;
    	CT.insert(root[x],root[fa],1,T,v[x]);
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p])	if (son!=fa)	rebuild(son,x);
    }
    int main(){
    	read();
    	int n=read(),m=read(),q=read();
    	for (int i=1;i<=n;i++)	v[i]=list[i]=read();
    	sort(list+1,list+1+n);
    	T=unique(list+1,list+1+n)-list-1;
    	for (int i=1;i<=n;i++)	v[i]=lower_bound(list+1,list+1+T,v[i])-list;
    	for (int i=1;i<=m;i++){
    		int x=read(),y=read();
    		LCT.link(x,y);
    		insert(x,y);
    	}
    	for (int i=1;i<=n;i++)	if (!belong[i])	rt[++Time]=i,dfs(i,0),LCT.make_root(i);
    	char s[5]; int Lastans=0;
    	for (int i=1;i<=q;i++){
    		scanf("%s",s);
    		if (s[0]=='L'){
    			int x=read()^Lastans,y=read()^Lastans;
    			if (size[belong[x]]>size[belong[y]])	swap(x,y);
    			LCT.link(x,y),size[belong[y]]+=size[belong[x]];
    			insert(x,y),rebuild(x,y);
    		}
    		if (s[0]=='Q'){
    			int x=read()^Lastans,y=read()^Lastans,k=read()^Lastans;
    			int lca=LCT.lca(x,y); LCT.make_root(rt[belong[x]]);
    			printf("%d
    ",Lastans=list[CT.Query(root[x],root[y],root[lca],root[f[lca]],1,T,k)]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    全局比对与动态规划
    汉诺塔游戏的递归解析
    scikit-learn 多分类混淆矩阵
    Python argparse 子命令
    优雅的查看json文件
    Python数据结构和算法学习笔记4
    Python学习笔记29
    Python学习笔记28
    Python数据结构和算法学习笔记3
    Python数据结构和算法学习笔记2
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9994259.html
Copyright © 2011-2022 走看看