zoukankan      html  css  js  c++  java
  • 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]
    ",l[i],r[i]);
            top=cnt2; sort(e1+1,e1+1+cnt2,cmp1); //printf("[%d]
    ",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]
    ",q[i].u,q[i].v,q[i].w);
            //for(int i=1;i<=cnt;i++) printf("[%d %d %d]
    ",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
    ",x,y,w,top);
                    top--;//printf("%d
    ",top);
                    if(deep[x]<deep[y]) swap(x,y);
                    L=l[x]; R=r[x]; W=w; //printf("%d %d %d
    ",L,R,W);
                    push_add(1,1,n);
                }//printf("~~~
    ");
                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
    ",ans[i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    webpack基本使用笔记
    gulp学习记录
    页面优化
    linux下使用indent整理代码
    C++中的getline()
    Sum of Two Integers
    TwoSum
    IDEA个人常用快捷键总结
    mysql数据库遇到的各种问题
    Python中*args 和**kwargs的用法和区别
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7158575.html
Copyright © 2011-2022 走看看