zoukankan      html  css  js  c++  java
  • P2486 [SDOI2011]染色 树链剖分 区间线段树

    输出格式:

    对于每个询问操作,输出一行答案。

    输入输出样例

    输入样例#1: 复制
    6 5
    2 2 1 2 1 1
    1 2
    1 3
    2 4
    2 5
    2 6
    Q 3 5
    C 2 1 1
    Q 3 5
    C 5 1 2
    Q 3 5
    
    输出样例#1: 复制
    3
    1
    2

    非常好的树链剖分 加区间线段树

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define pb push_back
    #define lson l,m,pos<<1
    #define rson m+1,r,pos<<1|1
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    typedef pair<int,int>pii;
    //////////////////////////////////
    const int N=2e6+10;
    int lef,rig;
    int t[N<<2],col[N<<2],le[N<<2],ri[N<<2],w[N],n,m,a,b,c,node[N];
    
    void up(int pos)
    {
        t[pos]=t[pos<<1]+t[pos<<1|1];
        if(ri[pos<<1]==le[pos<<1|1])t[pos]--;
        le[pos]=le[pos<<1];ri[pos]=ri[pos<<1|1];
    }
    void build(int l,int r,int pos)
    {
        col[pos]=0;
        if(l==r){t[pos]=1;le[pos]=ri[pos]=w[l];return;}
        int m=(l+r)>>1;
        build(lson);build(rson);up(pos);
    }
    void down(int pos)
    {
        if(col[pos])
        {
            t[pos<<1]=t[pos<<1|1]=1;
            col[pos<<1]=col[pos<<1|1]=col[pos];
            le[pos<<1]=le[pos<<1|1]=ri[pos<<1]=ri[pos<<1|1]=col[pos];
            col[pos]=0;
        }
    }
    void upsum(int L,int R,int v,int l,int r,int pos)
    {
        if(L<=l&&r<=R){t[pos]=1;le[pos]=ri[pos]=col[pos]=v;return;  }
        down(pos);int m=(l+r)>>1;
        if(L<=m)upsum(L,R,v,lson);
        if(R>m)upsum(L,R,v,rson);
        up(pos);
    }
    int qsum(int L,int R,int l,int r,int pos)//注意如果相邻两个区间有限制关系的话 要采用这种查询方式
    {
        if(l==L)lef=le[pos];if(r==R)rig=ri[pos];//记录一下左右端点
        if(L<=l&&r<=R){return t[pos];}
        down(pos);int m=(l+r)>>1;
    
        if(R<=m)return qsum(L,R,lson);
        if(L>m)return qsum(L,R,rson);
        
        int ans=qsum(L,R,lson)+qsum(L,R,rson);
        if(ri[pos<<1]==le[pos<<1|1] )ans--;
        up(pos);return ans;
    }
    int head[N<<1],pos,top[N],id[N],dep[N],fa[N],son[N],siz[N],cnt;
    struct Edge
    {
        int to,nex;
    }edge[N<<1];
    void add(int a,int b)
    {
        edge[++pos]=Edge{b,head[a]};
        head[a]=pos;
    }
    void dfs1(int x,int f)
    {
        dep[x]=dep[f]+1;fa[x]=f;siz[x]=1;son[x]=0;
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;
            if(v==f)continue;
            dfs1(v,x);
            siz[x]+=siz[v];
            if(siz[son[x]]<siz[v])son[x]=v;
        }
    }
    void dfs2(int x,int topf)
    {
        id[x]=++cnt;w[cnt]=node[x];top[x]=topf;
        if(son[x])dfs2(son[x],topf);
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;
            if(v==fa[x]||v==son[x])continue;
            dfs2(v,v);
        }
    }
    void UPsum(int x,int y,int v)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            upsum(id[top[x]],id[x],v,1,n,1);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        upsum(id[x],id[y],v,1,n,1);
    }
    int Qsum(int x,int y)
    {
        int ans=0;int L=-1,R=-1;//L R 表示的是 左链和右链  树链剖分查询的时候可能会两条链来回跳    显然不可能是三条链       
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y),swap(L,R);
            ans+=qsum(id[top[x]],id[x],1,n,1);
            if(L==rig)ans--;
            x=fa[top[x]];
            L=lef;
        }
        if(dep[x]>dep[y])swap(x,y),swap(L,R);
        ans+=qsum(id[x],id[y],1,n,1);
        if(rig==R)ans--;
        if(lef==L)ans--;//x与L绑定  Y与R绑定  此时x显然在上面  
        return ans;
    }
    char s[3];
    int main()
    {
        RII(n,m);
        rep(i,1,n)RI(node[i]);
        rep(i,1,n-1)RII(a,b),add(a,b),add(b,a);
        dfs1(1,1);dfs2(1,1);build(1,n,1);
        rep(i,1,m)
        {
            RS(s);
            if(s[0]=='C')RIII(a,b,c),UPsum(a,b,c);
            else RII(a,b),printf("%d
    ",Qsum(a,b));
        }
        return 0;
    }
    View Code
    
    
  • 相关阅读:
    自定义view 画圆
    自定义view imageviw
    XML Stream
    Pull刷新加载
    Fragment事物
    Viewpager小圆点
    单个水波纹扩散
    多个彩色水波纹扩散效果
    自定义view
    获取sd的音乐文件
  • 原文地址:https://www.cnblogs.com/bxd123/p/11174961.html
Copyright © 2011-2022 走看看