hdu4897 Little Devil I

http://www.elijahqi.win/archives/850
Problem Description
There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.

The devil likes to make thing in chaos. This kingdom’s road system is like simply a tree(connected graph without cycle). A road has a color of black or white. The devil often wants to make some change of this system.

In details, we call a path on the tree from a to b consists of vertices lie on the shortest simple path between a and b. And we say an edge is on the path if both its two endpoints is in the path, and an edge is adjacent to the path if exactly one endpoint of it is in the path.

Sometimes the devil will ask you to reverse every edge’s color on a path or adjacent to a path.

The king’s daughter, WJMZBMR, is also a cute loli, she is surprised by her father’s lolicon-like behavior. As she is concerned about the road-system’s status, sometimes she will ask you to tell there is how many black edge on a path.

Initially, every edges is white.

Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains an integer n, which is the size of the tree. The vertices be indexed from 1.
On the next n-1 lines, each line contains two integers a,b, denoting there is an edge between a and b.
The next line contains an integer Q, denoting the number of the operations.
On the next Q lines, each line contains three integers t,a,b. t=1 means we reverse every edge’s color on path a to b. t=2 means we reverse every edge’s color adjacent to path a to b. t=3 means we query about the number of black edge on path a to b.

T<=5.
n,Q<=10^5.
Please use scanf,printf instead of cin,cout,because of huge input.

Output
For each t=3 operation, output the answer in one line.

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

10
2 1 6
1 3 8
3 8 10
2 3 4
2 10 8
2 4 10
1 7 6
2 7 3
2 1 4
2 10 10

Sample Output
3

Hint
reverse color means change from white to black or vice virsa.

Author
WJMZBMR

Source
2014 Multi-University Training Contest 4

这题操作二大概非常骚 要求把两点之间所有临接边翻转 ,临接边意味着只有一个点是在我们的路径上

怎么去维护?看了别的blog表示原来这样,我对于轻边的维护在线段树中再加设一个数组rev2表示把这个点所有相连的边是否旋转的标记 但是边上不要求翻转,只翻转相邻的边

我们来看下下面的操作:

我们对于这个轻边,我们要分别去查他两端点对他的操作,直接用^进行处理,两端都操作等于没操作,剩下的同理

if (son[fa[x]]==x) rev1(root,id[x],id[x]);
if (son[y]) rev1(root,id[son[y]],id[son[y]]);
对于操作二中我们要做这样的操作,为什么,因为假如x->y的两头是重边,但是他们也满足条件啊,满足只有一个点在链上假如我查询的时候这俩(起点&终点)本来就在同一链上,那我岂不是两端的重链不能兼顾了,所以特殊写了一下

查询过程中:重边直接查询,要是遇到要跳了,那么这一定是轻边,我们先暴力查询在线段树中的值,但这可能不对,还要加上这个边两端对他的修改情况,但是我们只改答案,不改他在线段树中的权值,防止后面修改

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 110000
using namespace std;
inline int read(){
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
struct node{
    int y,z,next;
}data[N<<1];
struct node1{
    int l,r,left,right,rev1,rev2,sum;//rev1表示边权是否旋转rev2表示点权是否旋转 
}tree[N<<2];
int size[N],dep[N],fa[N],son[N],h[N],id[N],num,tp[N],n,m,root;
void dfs1(int x){
    size[x]=1;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;
        if (fa[x]==y) continue;
        dep[y]=dep[x]+1;fa[y]=x;dfs1(y);size[x]+=size[y];
        if (size[y]>size[son[x]]) son[x]=y;
    }
}
void dfs2(int x,int top){
    id[x]=++num;tp[x]=top;
    if (son[x]) dfs2(son[x],top);
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;
        if (fa[x]==y||son[x]==y) continue;
        dfs2(y,y);
    }
}
inline void update(int x){
    int l=tree[x].left,r=tree[x].right;
    tree[x].sum=tree[l].sum+tree[r].sum;
}
void build(int &x,int l,int r){
    x=++num;tree[x].l=l;tree[x].r=r;tree[x].rev1=tree[x].rev2=0;
    if (l==r){tree[x].sum=tree[x].left=tree[x].right=0;return;}int mid=l+r>>1;
    build(tree[x].left,l,mid);build(tree[x].right,mid+1,r);
    update(x);
} 
inline void pushdown1(int x){
    if (!tree[x].rev1) return;
    int l=tree[x].left,r=tree[x].right;
    tree[l].rev1^=1;tree[r].rev1^=1;
    tree[l].sum=tree[l].r-tree[l].l+1-tree[l].sum;
    tree[r].sum=tree[r].r-tree[r].l+1-tree[r].sum;
    tree[x].rev1=0;
}
void rev1(int x,int l,int r){
    if (l<=tree[x].l&&r>=tree[x].r){tree[x].rev1^=1;tree[x].sum=tree[x].r-tree[x].l+1-tree[x].sum;return;}
    int mid=tree[x].l+tree[x].r>>1;pushdown1(x);
    if (l<=mid) rev1(tree[x].left,l,r);
    if (r>mid) rev1(tree[x].right,l,r);
    update(x);
}
inline void pushdown2(int x){
    if (!tree[x].rev2) return;
    int l=tree[x].left,r=tree[x].right;
    tree[l].rev2^=1;tree[r].rev2^=1;tree[x].rev2=0;
}
void rev2(int x,int l,int r){
    if (l<=tree[x].l&&r>=tree[x].r){tree[x].rev2^=1;return;}
    int mid=tree[x].l+tree[x].r>>1;pushdown2(x);
    if (l<=mid) rev2(tree[x].left,l,r);
    if (r>mid) rev2(tree[x].right,l,r);
}
int qs(int x,int l,int r){
    if (l<=tree[x].l&&r>=tree[x].r) return tree[x].sum;
    int mid=tree[x].l+tree[x].r>>1;pushdown1(x);int ans1=0,ans2=0;
    if (l<=mid) ans1=qs(tree[x].left,l,r);
    if (r>mid) ans2=qs(tree[x].right,l,r);
    return ans1+ans2;
}
int qr(int x,int l){
    if (tree[x].l==tree[x].r) return tree[x].rev2;
    int mid=tree[x].l+tree[x].r>>1;pushdown2(x);
    if (l<=mid) return qr(tree[x].left,l);
    if(l>mid) return qr(tree[x].right,l);
}
int main(){
    freopen("hdu4897.in","r",stdin);
    int T=read();
    while (T--){
        n=read();memset(h,0,sizeof(h));memset(son,0,sizeof(son));num=1;
        for (int i=1;i<n;++i){
            int x=read(),y=read();
            data[++num].y=y;data[num].next=h[x];h[x]=num;
            data[++num].y=x;data[num].next=h[y];h[y]=num;
        }dep[1]=1;num=0;
        dfs1(1);dfs2(1,1);num=0;build(root,1,n);
        m=read();
        for (int i=1;i<=m;++i){
            int op=read(),x=read(),y=read();
            if (op==1) {
                while (tp[x]!=tp[y]){
                    if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
                    rev1(root,id[tp[x]],id[x]);x=fa[tp[x]];
                }
                if (id[x]>id[y]) swap(x,y);if (id[x]==id[y]) continue;
                rev1(root,id[x]+1,id[y]); 
                continue;
            }
            if (op==2){
                while (tp[x]!=tp[y]){
                    if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
                    rev2(root,id[tp[x]],id[x]);
                    if (son[x]) rev1(root,id[son[x]],id[son[x]]);
                    x=fa[tp[x]];
                }
                if (id[x]>id[y]) swap(x,y);
                rev2(root,id[x],id[y]);
                if (son[fa[x]]==x) rev1(root,id[x],id[x]);
                if (son[y]) rev1(root,id[son[y]],id[son[y]]);
                continue;
            }
            if (op==3){
                int ans=0;
                while (tp[x]!=tp[y]){
                    if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
                    ans+=qs(root,id[tp[x]]+1,id[x]);//重边 **注意+1 
                    ans+=qs(root,id[tp[x]],id[tp[x]])^qr(root,id[tp[x]])^qr(root,id[fa[tp[x]]]) ;
                    x=fa[tp[x]];
                } 
                if (id[x]>id[y])swap(x,y);if (id[x]==id[y]) {printf("%d\n",ans);continue;   }
                ans+=qs(root,id[x]+1,id[y]);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值