【题意】
【题解】
仙人掌,考虑圆方树。
正常构建圆方树并在每两个树边之间加入方点。
考虑使用每个方点维护与他相连的圆点信息,发现每个方点只能维护他的儿子圆点信息,否则会算重。
题目中修改操作即将两个圆点在新树上的路径上方点都加上v,即表示路径上所有环上的圆点都加v。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=6e5+5; const int mo=998244353; int n,m,q,last[N],size,dfn[N],low[N],siz,dui[N],ans[N],size1,last1[N],dax[N],f[N][20],len,cnt,st[N],toptop,Dfn[N],gaga; struct pigu { int dao,ne; }a[N<<3],b[N<<2]; inline void lingjiebiao(int x,int y) { a[++size].dao=y; a[size].ne=last[x]; last[x]=size; } inline void lingjiebiao2(int x,int y) { b[++size1].dao=y; b[size1].ne=last1[x]; last1[x]=size1; } inline int jia(int x,int y) { return (((x+y)%mo)+mo)%mo; } inline int read() { char c=getchar(); int x=0,f=1; while(!isdigit(c)) {if(c==‘-‘) f=-1;c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+c-‘0‘;c=getchar();} return x*f; } inline void tarjan(int now,int fa) { dfn[now]=low[now]=++cnt; st[++toptop]=now; for(int i=last[now];i;i=a[i].ne) { if(dfn[a[i].dao]==0) { tarjan(a[i].dao,now); low[now]=min(low[now],low[a[i].dao]); if(low[a[i].dao]==dfn[now]) { int k; ++siz; do { k=st[toptop--]; lingjiebiao2(k,siz); lingjiebiao2(siz,k); }while(k!=a[i].dao); lingjiebiao2(now,siz); lingjiebiao2(siz,now); } } else low[now]=min(low[now],dfn[a[i].dao]); } } int dep[N],sh[N],Siz[N]; inline int lowbit(int x) { return x&(-x); } inline void modify(int zai,int zhi) { for(int i=zai;i<=siz;i+=lowbit(i)) sh[i]=jia(sh[i],zhi); } inline int dquery(int x) { int ha=0; for(int i=x;i;i-=lowbit(i)) ha=jia(ha,sh[i]); return ha; } inline int query(int x) { return dquery(Dfn[x]+Siz[x]-1)-dquery(Dfn[x]-1)+mo; } inline void dfs(int now,int fa) { f[now][0]=fa;dep[now]=dep[fa]+1;Dfn[now]=++gaga;Siz[now]=1; for(int i=1;f[f[now][i-1]][i-1];i++) f[now][i]=f[f[now][i-1]][i-1]; for(int i=last1[now];i;i=b[i].ne) { if(b[i].dao==fa) continue; dfs(b[i].dao,now); Siz[now]+=Siz[b[i].dao]; } } inline int get_lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=19;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } signed main() { // freopen("cac.in","r",stdin); //freopen("cac.out","w",stdout); n=read();m=read();q=read(); for(int i=1,x,y;i<=m;i++) { x=read();y=read(); lingjiebiao(x,y); lingjiebiao(y,x); }siz=n; tarjan(1,0); dfs(1,0); for(int i=1,x,y,z,v;i<=q;i++) { x=read();y=read(); if(x==0) { z=read();v=read(); int lca=get_lca(y,z); modify(Dfn[y],v); modify(Dfn[z],v); modify(Dfn[lca],mo-v); if(f[lca][0]) modify(Dfn[f[lca][0]],mo-v); if(lca>n) ans[f[lca][0]]=jia(ans[f[lca][0]],v); else ans[lca]=jia(ans[lca],v); } else { int daan=jia(ans[y],f[y][0]?query(f[y][0]):0); cout<<daan<<"\n"; } } }
注意如果lca是圆点,则需将该圆点答案单独加上v,因为维护他的方点没法加。
查询即查询该点本身及他的父亲方点的权值即可,使用树链剖分或树上差分即可。
代码如下:
原文地址:https://www.cnblogs.com/betablewaloot/p/12210697.html
时间: 2024-11-02 06:30:19