Description
蜘蛛精大爷是世界上最爷的爷,ta的图论专著《蜘蛛精大爷教你学做人OI之图论》正在热卖,只要233美元一本,每人限购一本。。。。。。在某弱的不懈要求下,ta给某弱出了一道题,然而某弱太弱了,只好向你求助。
给你一张n个结点,m条边的无向图,每个结点都有一个整数权值。你需要执行一系列操作。操作分为三种,如下表所示。
操作
备注
D x (1<=x<=m)
删除编号为x的边。输入保证每条边至多被删除一次。
Q x k (1<=x<=n)
计算出结点x所在的联通块中,第k大的权值。如果不存在,输出0。
C x v (1<=x<=n)
把结点x的权值改为v。
操作序列的结束标志为单个字母E。结点编号为1到n,边的编号为1到m。
Input
输入第一行为两个整数n和m。
接下来n行每行一个整数,表示个节点的初始权值。
接下来m行每行两个整数,表示一条边的两个端点。
接下来是各条指令,以单个字母E结尾。
Output
对于每个Q指令,输出一行,包括一个计算结果。
Sample Input
3 3
10
20
30
1 2
2 3
1 3
D 3
Q 1 2
Q 2 1
D 2
Q 3 2
C 1 50
Q 1 1
E
Sample Output
20
30
0
50
Data Constraint
对于前50%的数据,n <= 1000,m <= 5000。
对于前10%的数据,没有D指令且没有C指令。
对于另20%的数据,没有D指令。
对于另20%的数据,没有C指令。
对于100%的数据,1 <= n <= 20000,0 <= m <= 60000,每个结点的权值为绝对值不超过
的整数,Q指令和C指令不超过200000条。
Solution
这题的数据范围没有完全给定,这就使得容易RE
首先把所有点的权值都看成正的,就是加上一个比较大的常数,输出时减掉即可
存有多少个数并且要求出第K大,用权值线段树比较方便,splay也可以
而分解线段树我没听说过,所以就反过来做,线段树合并
那么就很简单了,稍微细心码一码,注意好细节,这种题小数据对了大数据也不会错
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 20100
#define INF 2147483647ll
#define ll long long
using namespace std;
struct node{
int l,r,d;
}t[N*100];
int ans[N*10],n,m,r[N],edg[N*3][2],bz[N*3],q[N*100][3],fa[N],tot,c[N];
void change(int v,ll i,ll j,ll x,int z)
{
t[v].d+=z;
if(i==j) return;
ll m=(i+j)/2;
if(x<=m) t[v].l=t[v].l==0?++tot:t[v].l,change(t[v].l,i,m,x,z);
else t[v].r=t[v].r==0?++tot:t[v].r,change(t[v].r,m+1,j,x,z);
}
ll get(int v,ll i,ll j,int x)
{
if(i==j) return i;
if(t[v].d<x) return INF;
ll m=(i+j)/2;
if(t[t[v].r].d>=x) return get(t[v].r,m+1,j,x);
else return get(t[v].l,i,m,x-t[t[v].r].d);
}
void hb(int v1,int v2,ll i,ll j)
{
if(i==j) {t[v1].d+=t[v2].d;return;}
ll m=(i+j)/2;
if(t[t[v1].l].d==0) t[v1].l=t[v2].l;
else if(t[t[v2].l].d!=0) hb(t[v1].l,t[v2].l,i,m);
if(t[t[v1].r].d==0) t[v1].r=t[v2].r;
else if(t[t[v2].r].d!=0) hb(t[v1].r,t[v2].r,m+1,j);
t[v1].d=t[t[v1].l].d+t[t[v1].r].d;
}
int gf(int x){return fa[x]==0?x:fa[x]=gf(fa[x]);}
void he(int x,int y)
{
x=gf(x),y=gf(y);
if(x==y) return;
fa[y]=x;
hb(r[x],r[y],1,INF+INF);
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d",&c[i]);
fo(i,1,m) scanf("%d%d\n",&edg[i][0],&edg[i][1]);
int i=0;
while(1)
{
char ch;scanf("%c",&ch);
if(ch=='E') break;
i++;
if(ch=='D') q[i][0]=0,scanf("%d\n",&q[i][1]),bz[q[i][1]]=1;
if(ch=='C') q[i][0]=1,scanf("%d%d\n",&q[i][1],&q[i][2]),swap(c[q[i][1]],q[i][2]);
if(ch=='Q') q[i][0]=2,scanf("%d%d\n",&q[i][1],&q[i][2]),ans[0]++;
}
fo(i,1,n) r[i]=++tot,change(r[i],1,INF+INF,c[i]+INF,1);
fo(i,1,m) if(bz[i]==0) he(edg[i][0],edg[i][1]);
int at=ans[0];
for(;i;i--)
{
if(q[i][0]==0) he(edg[q[i][1]][0],edg[q[i][1]][1]);
if(q[i][0]==1)
{
int rt=r[gf(q[i][1])];
change(rt,1,INF+INF,c[q[i][1]]+INF,-1);
change(rt,1,INF+INF,q[i][2]+INF,1);
c[q[i][1]]=q[i][2];
}
if(q[i][0]==2) ans[ans[0]--]=(int)(get(r[gf(q[i][1])],1,INF+INF,q[i][2])-INF);
}
fo(i,1,at) printf("%d\n",ans[i]);
}