[51nod2004]终结之时

Description

“将世界终结前最后的画面,深深刻印进死水般的心海.”
祈愿没有得到回应,雷声冲破云霄,正在祈愿的洛天依受到了极大的打击。
洛天依叹了口气,说:”看来这个世界正如我之前所说的一样,早已失去一切生机”
你沉默了下来,没有说什么话,只是静静地坐在洛天依的身旁,一同观赏这末日之景.
天空被云朵覆盖,一朵具有强大能量的云映入你们的眼帘,这是始云!是抽取世界能量的最重要的一朵云!但是洛天依明显没有破坏这朵云的斗志了,你也只好静静地观赏.
这个世界被吸取的能量从始云开始传递,通过愿望银线输送到各个积雨云上,每朵积雨云即作为能量中转点,又作为能量湮灭点。如此,整片天空构成了一个巨大的能量输送网络。很巧,我们可以用图论中的有向图来描述这个网络.
我们定义始云的编号为1.
对于一朵积雨云y,如果从始云开始到这个点的所有路径都经过了点x,那么我们称x是y的支配云,x支配y,y被x支配。显然一个点的支配云可能有多个且至少有两个。
旁边的洛天依此时非常惊讶,因为她发现不同的积雨云的能量强度不一样!
洛天依用正整数来描述这个能量的强度,同时起名为湮灭能量数.
也就是说在这个云朵湮灭的能量的单位数目.
然而整个网络中的云湮灭的能量数在不断的变化中,变化的情况如下:
C 1 u w有一股能量在云朵u中湮灭了w的能量.
C 2 u w点u支配的所有云朵上都湮灭了w能量
C 3 u w支配点u的所有的云朵上都湮灭了w的能量
“最后一次求你了,为我推演一下这毁灭能量的变化吧.”
洛天依一共有四种请求:
Q 1 u 询问u支配的所有的云朵的湮灭能量数之和.
Q 2 u 询问支配u的所有的云朵的湮灭能量数权值之和.
Q 3 s x1 x2 … xs 询问所有支配了其中任一云朵的云朵的湮灭能量数权值之和.
R k让状态回到k次变化之前.若k大于已经执行的操作数,则视为回到初始状态.
你自然不忍心拒绝洛天依,于是你打算圆满完成这个任务.
n≤50000,q≤100000,∑s≤50000,m≤100000,w≤1000

Solution

见过的最简单的F题[逃]
然而当时打的时候心态爆炸WA就没有调试,现在看来血亏_ (:з」∠) _
我写倍增求LCA,结果写着写着忘了写预处理了QwQ
题解很简单,只要你会支配树就是简单题
Q3的话直接把所有关键点按照dfs序排序然后直接减去所有相邻节点的lca到根的路径上的的权值之和就好了。

Code

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=lst[a];i;i=nxt[i])
using namespace std;

typedef long long ll;

int read() {
        char ch;
        for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
        int x=ch-'0';
        for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
        return x;
}

void write(ll x) {
        if (!x) {puts("0");return;}
        char ch[20];int tot=0;
        for(;x;x/=10) ch[++tot]=x%10+'0';
        fd(i,tot,1) putchar(ch[i]);
        puts("");
}

const int N=5*1e4+5;

typedef vector<int> vec;
#define pb(a) push_back(a)
vec pre[N],dom[N];

int lst[N],nxt[N<<1],t[N<<1],l;
void add(int x,int y) {
        t[++l]=y;nxt[l]=lst[x];lst[x]=l;
}

int n,m,x,y,semi[N],idom[N];

int id[N],dfn[N],fa[N],tot;
void dfs(int x) {
        dfn[x]=++tot;id[tot]=x;
        rep(i,x) {
            pre[t[i]].pb(x);
            if (!dfn[t[i]]) {
                fa[t[i]]=x;
                    dfs(t[i]);
            } 
        }
}

int father[N],val[N];
int get(int x) {
    if (father[x]==x) return x;
        int y=get(father[x]);
        if (dfn[semi[val[father[x]]]]<dfn[semi[val[x]]]) val[x]=val[father[x]];
        return father[x]=y;
}

int smin(int x,int y) {return dfn[x]<dfn[y]?x:y;}

void solve() {
        fd(i,tot,2) {
            int x=id[i];
            if (!pre[x].empty())
                    fo(j,0,pre[x].size()-1)
                        if (dfn[pre[x][j]]<dfn[x]) semi[x]=smin(semi[x],pre[x][j]);
                        else {
                                get(pre[x][j]);
                                semi[x]=smin(semi[x],semi[val[pre[x][j]]]);
                        }
            father[x]=fa[x];dom[semi[x]].pb(x);
            if (!dom[fa[x]].empty())
                    fo(j,0,dom[fa[x]].size()-1) {
                        int v=dom[fa[x]][j];get(v);
                        int u=val[v];
                        idom[v]=(dfn[semi[u]]<dfn[semi[v]])?u:fa[x];
                    }
        }
        fo(i,2,tot) {
            int x=id[i];
            if (idom[x]!=semi[x]) idom[x]=idom[idom[x]];
        }
}

int size[N],f[N][16],dep[N],son[N],a[N];
int top[N],w[N],cnt,tmp;

void travel(int x,int y) {
    int k=0;size[x]=1;f[x][0]=y;dep[x]=dep[y]+1; 
    rep(i,x)
        if (t[i]!=y) {
            travel(t[i],x);
            if (size[t[i]]>k) k=size[t[i]],son[x]=t[i];
            size[x]+=size[t[i]];
        }
} 

void make(int x,int y) {
    top[x]=y;dfn[x]=++cnt;w[cnt]=x;
    if (!son[x]) return;
    make(son[x],y);
    rep(i,x)
        if (t[i]!=f[x][0]&&t[i]!=son[x])
            make(t[i],t[i]);
}

ll tr[N<<6];
int now,root[N],tag[N<<6],ls[N<<6],rs[N<<6],bl[N<<6];

struct node{int id,v;}b[N];
bool cmp(node x,node y) {return x.id<y.id;}

int newnode(int v,int rt) {
    tr[++tmp]=tr[v];tag[tmp]=tag[v];
    ls[tmp]=ls[v];rs[tmp]=rs[v];
    bl[tmp]=rt;
    return tmp; 
} 

void update(int &v,int l,int r,int z,int rt) {
    if (bl[v]!=rt) v=newnode(v,rt);
    tr[v]+=(ll)(r-l+1)*z;
    tag[v]+=z;
}

void down(int v,int l,int r) {
    int mid=l+r>>1;
    if (tag[v]) {
        update(ls[v],l,mid,tag[v],bl[v]);
        update(rs[v],mid+1,r,tag[v],bl[v]);
        tag[v]=0;
    }
}

void build(int &v,int l,int r) {
    v=++tmp;
    if (l==r) {tr[v]=a[w[l]];return;}
    int mid=l+r>>1;
    build(ls[v],l,mid);
    build(rs[v],mid+1,r);
    tr[v]=tr[ls[v]]+tr[rs[v]];
}

void modify(int &v,int l,int r,int x,int y,int z) {
    v=newnode(v,now);
    if (l==x&&r==y) {update(v,l,r,z,now);return;}
    down(v,l,r);int mid=l+r>>1;
    if (y<=mid) modify(ls[v],l,mid,x,y,z);
    else if (x>mid) modify(rs[v],mid+1,r,x,y,z);
    else modify(ls[v],l,mid,x,mid,z),modify(rs[v],mid+1,r,mid+1,y,z);
    tr[v]=tr[ls[v]]+tr[rs[v]];
}

ll query(int v,int l,int r,int x,int y) {
    if (!v) return 0;
    if (l==x&&r==y) return tr[v];
    int mid=l+r>>1;down(v,l,r);
    if (y<=mid) return query(ls[v],l,mid,x,y);
    else if (x>mid) return query(rs[v],mid+1,r,x,y);
    else return query(ls[v],l,mid,x,mid)+query(rs[v],mid+1,r,mid+1,y);
}

ll find(int x) {
    ll ans=0;
    while (x) {
        ans+=query(root[now],1,n,dfn[top[x]],dfn[x]);
        x=f[top[x]][0];
    }
    return ans;
}

int lca(int x,int y) {
    if (dep[x]<dep[y]) swap(x,y);
    fd(j,15,0) if (dep[f[x][j]]>dep[y]) x=f[x][j];
    if (dep[x]!=dep[y]) x=f[x][0];
    fd(j,15,0) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
    return (x==y)?x:f[x][0]; 
}

int main() {
    n=read();m=read();
    fo(i,1,n) a[i]=read();
    fo(i,1,m) {
        x=read();y=read();
        add(x,y);
    }
    fo(i,1,n) father[i]=val[i]=semi[i]=i;
    dfs(1);solve();
    fo(i,1,n) lst[i]=0;l=0;
    fo(i,2,tot) add(idom[i],i);
    travel(1,0);make(1,1);
    build(root[0],1,n);
    fo(j,1,15)
        fo(i,1,n)
            f[i][j]=f[f[i][j-1]][j-1];
    for(int q=read();q;q--) {
        char ch;
        for(ch=getchar();ch<'A'||ch>'Z';ch=getchar());
        if (ch=='C') {
            int opt=read();
            root[now+1]=root[now];now++;
            if (opt==1) {
                int x=read(),y=read();
                modify(root[now],1,n,dfn[x],dfn[x],y);
            }
            if (opt==2) {
                int x=read(),y=read();
                modify(root[now],1,n,dfn[x],dfn[x]+size[x]-1,y);
            }
            if (opt==3) {
                int x=read(),y=read();
                while (x) {
                    modify(root[now],1,n,dfn[top[x]],dfn[x],y);
                    x=f[top[x]][0];
                }
            }
        }
        if (ch=='Q') {
            int opt=read();
            if (opt==1) {
                int x=read();
                write(query(root[now],1,n,dfn[x],dfn[x]+size[x]-1));
            }
            if (opt==2) {
                int x=read();
                write(find(x));
            }
            if (opt==3) {
                int sz=read();
                fo(i,1,sz) {
                    b[i].v=read();
                    b[i].id=dfn[b[i].v];
                }
                sort(b+1,b+sz+1,cmp);
                ll ans=0;
                fo(i,1,sz) {
                    ans+=find(b[i].v);
                    if (i>1) ans-=find(lca(b[i].v,b[i-1].v));
                }
                write(ans);
            }
        }
        if (ch=='R') {
            int x=read();
            now=max(0,now-x);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值