codechef T6 Pishty and tree dfs序+线段树
PSHTTR: Pishty 和城堡
题目描述 Pishty 是生活在胡斯特市的一个小男孩。胡斯特是胡克兰境内的一个古城,以其中世纪风格 的古堡和非常聪明的熊闻名全国。 胡斯特的镇城之宝是就是这么一座古堡,历史上胡斯特依靠这座古堡抵挡住了疯人国的大军。 对于 Pishty 来说,真正吸引他的是古堡悠长的走廊和高耸的钟楼,以及深藏于其中的秘密…… 古堡可以用一棵 N 个节点的树的描述,树中有 N −1 条无向边,每条边有一个魔法数字 C。 当一个旅游团参观古堡时,他们会选择树上 U 到 V 的路径游览。他们认为,如果一条边的魔 法数字不超过 K,那么这条边是有趣的。而一条路径的吸引力就是路径上所有有趣的边的魔法数 字的异或和。 胡克兰的国王希望大力发展旅游业,因此他下令求出所有旅游团的游览路径的吸引力。而 Pishty立志成为国王身边的骑士,便自告奋勇承担了这一任务。但旅游团实在太多了,他也算不过 来。所以,请你帮Pishty解决这一问题:给定 M 个旅游团的旅游路径,请你求出路径的吸引力。
输入格式
输入的第一行包含一个整数 T,代表测试数据的组数。接下来是 T 组数据。 每组数据的第一行包含一个整数 N,代表树的节点个数。 接下来 N −1 行,每行描述一条边。每行包含三个整数 U,V,C,代表节点 U 和 V 之间连有 一条魔法数字为 C 的边。 接下来一行包含一个整数 M,代表旅游团的数量。 接下来 M 行,每行包含三个整数 U,V,K,描述一个旅游团。
输出格式
对于每个旅游团,输出一行,包含一个整数,代表其路径的吸引力。
数据范围和子任务 • 1 ≤ T ≤ 5 • 1 ≤ N,M ≤ 105
• 1 ≤ U,V ≤ N • 1 ≤ C,K ≤ 109
子任务 1(10 分): • 1 ≤ N,M ≤ 10
子任务 2(20 分): • 1 ≤ N,M ≤ 103
子任务 3(70 分): • 无附加限制
样例数据
输入
1
5
1 2 1
2 3 2
2 4 5
3 5 10
6
5 4 5
5 4 10
5 4 1
1 2 1
4 1 10
1 5 8
输出
7
13
0
1
4
3
首先我们要了解异或的三个性质
1.a^b=b^a
2.(a^b)^c=a^(b^c)
3.a^a=0
这样之后我们可以发现 两个点之间路径的异或和可以转换 成两个点到根节点的异或和的值 异或起来就是答案
我们可以强制一为根 然后根据dfs序记录每个点包含的区间(也就是他在树上的子树范围) 方便做区间处理
然后我们可以离线处理答案 把答案按限制大小从小到达排一波 每次把符合的边插进去 找到这条边两个端点深度较深的那个点
注意一定是深度较深 也就是在树上位置较下边的点 这个画图很容易证明
然后把他包含的区间(也就是树上他的子树)进行一波区间异或也就是lazy 然后单点查询就可以啦
这道题调了很久 最后发现是sort的时候反向边的相对位置发生了改变 mdzz
最后贴一波代码咯
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=1<<17; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int T,n,m; int L,R,W,top; int cnt,cnt2,first[M],deep[M]; struct node{int to,from,next,w;}e[2*M],e1[2*M]; bool cmp1(node a,node b){return a.w>b.w;} void ins(int a,int b,int w){cnt++; e[cnt].from=a; e[cnt].to=b; e[cnt].w=w; e[cnt].next=first[a]; first[a]=cnt;} void insert(int a,int b,int w){ins(a,b,w); ins(b,a,w);} struct note{int u,v,w,pos;}q[M]; bool cmp2(note a,note b){return a.w<b.w;} int l[M],r[M],sum; int v[2*M],ans[M]; void prepare(){ cnt2=cnt=0; memset(first,0,sizeof(first)); L=0; R=0; W=0; sum=0; memset(v,0,sizeof(v)); memset(deep,0,sizeof(deep)); deep[1]=1; } void dfs(int x){ l[x]=++sum; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(!deep[now]) deep[now]=deep[x]+1,dfs(now); } r[x]=sum; } void down(int x,int l,int r){ if(l==r) return ; int k=v[x]; v[x]=0; v[x<<1]^=k; v[x<<1^1]^=k; } void push_add(int x,int l,int r){ if(L<=l&&r<=R){ v[x]^=W; return ; } if(l==r) return ; if(v[x]) down(x,l,r); int mid=(l+r)>>1;; if(L<=mid) push_add(x<<1,l,mid); if(R>mid) push_add(x<<1^1,mid+1,r); } int find(int x,int l,int r,int k){ if(l==r) return v[x]; int mid=(l+r)>>1; if(v[x]) down(x,l,r); if(k<=mid) return find(x<<1,l,mid,k); else return find(x<<1^1,mid+1,r,k); } int main() { int x,y,w; T=read(); while(T--){ prepare(); n=read(); for(int i=1;i<n;i++){ x=read(),y=read(),w=read(),insert(x,y,w); cnt2++; e1[cnt2].to=y; e1[cnt2].from=x; e1[cnt2].w=w; } dfs(1); //for(int i=1;i<=n;i++) printf("[%d %d]\n",l[i],r[i]); top=cnt2; sort(e1+1,e1+1+cnt2,cmp1); //printf("[%d]\n",cnt); m=read(); for(int i=1;i<=m;i++) q[i].u=read(),q[i].v=read(),q[i].w=read(),q[i].pos=i; sort(q+1,q+1+m,cmp2); //for(int i=1;i<=m;i++) printf("[%d %d %d]\n",q[i].u,q[i].v,q[i].w); //for(int i=1;i<=cnt;i++) printf("[%d %d %d]\n",e[i].from,e[i].to,e[i].w); for(int i=1;i<=m;i++){ int mx=q[i].w; while(top&&e1[top].w<=mx){ x=e1[top].from; y=e1[top].to; w=e1[top].w; //printf("[%d %d %d] %d\n",x,y,w,top); top--;//printf("%d\n",top); if(deep[x]<deep[y]) swap(x,y); L=l[x]; R=r[x]; W=w; //printf("%d %d %d\n",L,R,W); push_add(1,1,n); }//printf("~~~\n"); int sum1=find(1,1,n,l[q[i].u]),sum2=find(1,1,n,l[q[i].v]); ans[q[i].pos]=sum1^sum2; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); } return 0; }