BZOJ 3221 [Codechef FEB13] Obserbing the tree树上询问 树链剖分 主席树维护区间加等差数列

来源:互联网 发布:网络教育文凭事业单位 编辑:程序博客网 时间:2024/06/05 08:57

题目大意:给出一棵树,每个结点初始均为0,要求支持以下操作:路径加等差数列,询问路径上结点权值和,回到之前的某个版本,强制在线。

调到吐血。

很明显可以看出需要树链剖分+主席树来解决,由于需要在主席树上区间修改所以标记永久化。
区间维护等差数列需要在每个结点上维护 首项 和 公差。
树链剖分时在路径上加等差数列需要讨论,细节比较多,详见代码。
(我看错题了..注意回到某个版本并不舍弃在这之间的版本)

#include <cstdio>#include <algorithm>#include <cstring>#define N 150005#define int long longusing namespace std;typedef long long LL;int time_clock,tot_time;namespace Segment_Tree {    struct Node {        Node* ch[2];        int sum,a0,d,l,r,ver;        Node(Node* tmp=NULL) {            if(tmp) {                ch[0]=tmp->ch[0];                ch[1]=tmp->ch[1];                sum=tmp->sum;                a0=tmp->a0;                d=tmp->d;                l=tmp->l;                r=tmp->r;                ver=tmp->ver;            }            else {                ch[0]=ch[1]=NULL;                sum=l=r=a0=d=ver=0;            }        }        void* operator new(size_t) {            static Node *C,*mempool;            if(C==mempool) mempool=(C=new Node[1<<20])+(1<<20);            return C++;        }    }*root[N];    void init(Node*& o,int l,int r) {        o=new Node();        o->l=l, o->r=r;        if(l==r) return ;        int mid=l+r>>1;        init(o->ch[0],l,mid), init(o->ch[1],mid+1,r);        return ;    }    int query(Node* o,int l,int r) {        int tmp=(2*o->a0+o->d*(l+r-2*o->l))*(r-l+1)/2;        if(o->l==l && o->r==r) return o->sum+tmp;        int mid=o->l+o->r>>1;        if(r<=mid) return tmp+query(o->ch[0],l,r);        if(l>mid) return tmp+query(o->ch[1],l,r);        return tmp+query(o->ch[0],l,mid)+query(o->ch[1],mid+1,r);    }    void change(Node*& o,int l,int r,int a0,int d) {        if(o->ver!=time_clock) {            Node* tmp=o;            o=new Node(tmp);            o->ver=time_clock;        }        if(o->l==l && o->r==r) {            o->a0+=a0;            o->d+=d;            return ;        }        o->sum+=(2*a0+d*(r-l))*(r-l+1)/2;        int mid=o->l+o->r>>1;        if(r<=mid) change(o->ch[0],l,r,a0,d);        else if(l>mid) change(o->ch[1],l,r,a0,d);        else change(o->ch[0],l,mid,a0,d), change(o->ch[1],mid+1,r,a0+d*(mid+1-l),d);        return ;    }}namespace Tree_Partition {    struct Edge {        int from,to,nxt;        Edge() {}        Edge(int _from,int _to,int _nxt):from(_from),to(_to),nxt(_nxt) {}    }e[N*2];    int fir[N],tot=-1;    void Add_Edge(int x,int y) {        e[++tot]=Edge(x,y,fir[x]), fir[x]=tot;        e[++tot]=Edge(y,x,fir[y]), fir[y]=tot;        return ;    }    int dfs_clock,pa[N],top[N],dpt[N],siz[N],son[N],pos[N],seq[N];    void dfs1(int x) {        siz[x]=1;        dpt[x]=dpt[pa[x]]+1;        for(int i=fir[x];~i;i=e[i].nxt) {            if(e[i].to==pa[x]) continue;            pa[e[i].to]=x;            dfs1(e[i].to);            siz[x]+=siz[e[i].to];            if(siz[son[x]]<siz[e[i].to]) son[x]=e[i].to;        }        return ;    }    void dfs2(int x) {        pos[x]=++dfs_clock;        seq[dfs_clock]=x;        if(son[pa[x]]==x) top[x]=top[pa[x]];        else top[x]=x;        if(son[x]) dfs2(son[x]);        for(int i=fir[x];~i;i=e[i].nxt) {            if(e[i].to==pa[x] || e[i].to==son[x]) continue;            dfs2(e[i].to);        }        return ;    }    int LCA(int x,int y) {        while(top[x]!=top[y]) {            if(dpt[top[x]]<dpt[top[y]]) swap(x,y);            x=pa[top[x]];        }        if(dpt[x]<dpt[y]) swap(x,y);        return y;    }    int query(int x,int y) {        using Segment_Tree :: query;        using Segment_Tree :: root;        int ans=0;        while(top[x]!=top[y]) {            if(dpt[top[x]]<dpt[top[y]]) swap(x,y);            ans+=query(root[time_clock],pos[top[x]],pos[x]);            x=pa[top[x]];        }        if(dpt[x]<dpt[y]) swap(x,y);        ans+=query(root[time_clock],pos[y],pos[x]);        return ans;    }    void change(int x,int y,int a0,int d) {        using Segment_Tree :: root;        using Segment_Tree :: change;        tot_time++;        root[tot_time]=root[time_clock];        time_clock=tot_time;        int lca=LCA(x,y);        int an=a0+d*(dpt[x]+dpt[y]-2*dpt[lca]);        while(top[x]!=top[y]) {            if(dpt[top[x]]>dpt[top[y]]) {                change(root[time_clock],pos[top[x]],pos[x],a0+d*(dpt[x]-dpt[top[x]]),-d);                a0+=(dpt[x]-dpt[top[x]]+1)*d;                x=pa[top[x]];            }            else {                change(root[time_clock],pos[top[y]],pos[y],an-d*(dpt[y]-dpt[top[y]]),d);                an-=(dpt[y]-dpt[top[y]]+1)*d;                y=pa[top[y]];            }        }        if(dpt[x]>dpt[y]) change(root[time_clock],pos[y],pos[x],an,-d);        else change(root[time_clock],pos[x],pos[y],a0,d);        return ;    }}#undef intint main() {    #define int long long    int n,m;    scanf("%lld%lld",&n,&m);    using namespace Tree_Partition;    memset(fir,-1,sizeof fir);    for(int i=1;i<n;i++) {        int x,y;        scanf("%lld%lld",&x,&y);        Add_Edge(x,y);    }    dfs1(1), dfs2(1);    Segment_Tree :: init(Segment_Tree :: root[0],1,n);    int last_ans=0;    while(m--) {        char mode[5];        int x,y,a0,d;        scanf("%s",mode);        if(mode[0]=='c') {            scanf("%lld%lld%lld%lld",&x,&y,&a0,&d);            x^=last_ans, y^=last_ans;            change(x,y,a0,d);        }        else if(mode[0]=='q') {            scanf("%lld%lld",&x,&y);            x^=last_ans, y^=last_ans;            printf("%lld\n",last_ans=query(x,y));        }        else {            scanf("%lld",&x);            x^=last_ans;            time_clock=x;        }    }    return 0;}
0 0
原创粉丝点击