Description
Mr. Panda 有 N 个花园,编号从 1 到 N 。对于编号为 i 的花园,花园里只有一朵花,颜色为 ci 。花园与花园之间有道路连接(道路是双向的)。每条道路都有一个花费,表示经过该道路花费的时间。
Mr. Panda 喜欢在他的N个花园中转悠,然后采尽可能多的同种颜色的花。然而,有时候他并不想花太多时间走同一段路。现在问题来了,每一次 Mr. Panda 会告诉你:他从哪个花园开始出发和他能忍受的走同一段路的花费的最大值w(也就是说,只有费用不超过w的道路可以通行)。
请你判断Mr. Panda最多能采到的花是哪种颜色的花。如果有多种颜色符合条件,选择颜色编号最小的输出。
Input
第一行包含三个整数 N,M,type ,分别表示花园数目、道路数目和数据是否加密。
接下来一行N个整数,第i个整数表示第i个花园中的花的颜色
接下来M行表示花园中的道路,每行三个整数 x,y,w ,表示有一条花费为w的道路连接x号花园和y号花园。
接下来一个整数Q,表示Q组询问。
接下来Q行,每行一组询问x, w,表示Mr. Panda从x号花园出发,他能忍受的走同一段路的花费的最大值w。如果type=0,则输入给定的x和w均为真实的x和w。如果type=1,则输入给定的x和w均为加密后的x和w。设上一次询问的答案为last,则需要将x和w均与last异或后才能得到真实的x和w。特别地,对于第一组询问,last = 0。
Output
Sample Input
【样例输入1】
5 6 0
2 1 1 3 2
1 2 2
1 3 4
2 3 7
3 4 5
4 5 6
5 3 3
4
1 1
2 2
4 4
5 8
【样例输入2】
5 6 1
2 1 1 3 2
1 2 2
1 3 4
2 3 7
3 4 5
4 5 6
5 3 3
4
1 1
0 0
5 5
6 11
Sample Output
【样例输出1】
2
1
3
1
【样例输出2】
2
1
3
1
HINT
【样例解释】
第二组数据解密后即是第一组数据。
第一组询问:没有路可以走,故从1号点只能采颜色2的花1朵,故答案为2。
第二组询问:第1条路可以走,故从2号点开始可以采颜色1的花1朵,颜色2的花1朵,故答案为1。
第三组询问:第1、2、6条路可以走,故从4号点开始可以采颜色3的花1朵,故答案为3。
第四组询问:所有路都可以走,故从5号点开始可以采颜色1的花2朵,颜色2的花2朵,颜色3的花1朵,故答案为1。
【数据范围与约定】
本题设有5个测试点。
第1个测试点: N≤2×103,M,Q≤4×103,type=1
第2个测试点: N≤5×104,M,Q≤1×105,type=0
第3个测试点: N≤1×105,M,Q≤2×105,type=0
第4个测试点: N≤5×104,M,Q≤1×105,type=1
第5个测试点: N≤1×105,M,Q≤2×105,type=1
对于所有数据:
1≤N≤105
1≤M,Q≤2×105
1≤x,y,ci≤N
1≤w≤106
解法:可持久化并查集、可持久化线段树。
考虑Kruscal的过程,合并两个节点时,新建一个节点后把原来的节点视为新节点的左右儿子。
这样可以建出一个树,每次询问相当于询问这棵树上一个子树颜色的众数。线段树合并(启发式合并)即可。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<map> using namespace std; const int Maxn=1e6+50; const int Maxm=5e6+50; const int INF=0x3f3f3f3f; inline int read() { char ch=getchar();int i=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();} return i*f; } struct tr { int lc,rc; pair<int,int >mx; }tr[Maxm]; int n,m,type,cnt,last,num[Maxn]; int father[Maxn],fw[Maxn],sze[Maxm],rt[Maxn]; struct node { int x,y,w; friend inline bool operator <(const node &a,const node &b) { return a.w<b.w; } }edge[Maxn]; map<int,int>to[Maxn]; inline int getf(int x,int w=INF) { if(father[x]==x||w<fw[x])return x; return getf(father[x],w); } inline int Merge(int l,int r,int x1,int x2) { if(!x1)return x2; if(!x2)return x1; int x=++cnt; if(l==r)tr[x].mx=make_pair(tr[x1].mx.first+tr[x2].mx.first,tr[x1].mx.second); else { int mid=(l+r)>>1; tr[x].lc=Merge(l,mid,tr[x1].lc,tr[x2].lc); tr[x].rc=Merge(mid+1,r,tr[x1].rc,tr[x2].rc); tr[x].mx=max(tr[tr[x].lc].mx,tr[tr[x].rc].mx); } return x; } inline int Build(int l,int r,int val) { int x=++cnt; tr[x].mx=make_pair(1,-val); if(l!=r) { int mid=(l+r)>>1; if(val<=mid) tr[x].lc=Build(l,mid,val); else tr[x].rc=Build(mid+1,r,val); } return x; } inline int Query(int x,int w) { int f=getf(x,w); auto it=to[f].upper_bound(w); it--; return -tr[it->second].mx.second; } int main() { //freopen("lx.in","r",stdin); n=read(),m=read(),type=read(); for(int i=1;i<=n;i++) { num[i]=read(); father[i]=i; fw[i]=0; sze[i]=1; to[i][0]=rt[i]=Build(1,n,num[i]); } for(int i=1;i<=m;i++) { edge[i].x=read(),edge[i].y=read(),edge[i].w=read(); } sort(edge+1,edge+m+1); for(int i=1;i<=m;i++) { int x=edge[i].x,y=edge[i].y,w=edge[i].w; x=getf(x),y=getf(y); if(x!=y) { if(sze[x]<sze[y])swap(x,y); father[y]=x;sze[x]+=sze[y];fw[y]=w; to[x][w]=rt[x]=Merge(1,n,rt[x],rt[y]); } } m=read(); while(m--) { int x=read(),w=read(); if(type)x^=last,w^=last; printf("%d\n",last=Query(x,w)); } }