loj 2011
题意:一棵树 有两种操作 1.选定一个点 且这个点的权值随着时间的增加而增加1
2.查询一条路径上点的个数和权值大于C的个数
题解:刚开始没想到离线的做法 认为可以大力线段树 n(logn)^3 然而显然过不去 被韦神教育后也考虑过树上莫队的写法 然而n^(5/3)然并卵 偷偷瞄了一眼题解
发现我们可以这样离线一下 然后少掉一个log 对于每个querty我们找到临界位置max(0,i-C-1) 这样的话 我们只要去找当临界位置的时候在这条链上的被更新的点的个数 这样的话 我们树状数组维护就ojbk了
#include <bits/stdc++.h> #define ll long long #define s second #define f first #define pii pair<int,int> #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=2e5+10; using namespace std; vector<int>vec[MAXN]; int son[MAXN],fa[MAXN],num[MAXN],dep[MAXN]; int n,q; void dfs1(int v,int pre,int deep){ num[v]=1;dep[v]=deep+1;fa[v]=pre; for(int i=0;i<vec[v].size();i++){ int u=vec[v][i]; if(u!=pre){ dfs1(u,v,deep+1); num[v]+=num[u]; if(son[v]==-1||num[son[v]]<num[u]) son[v]=u; } } } int tp[MAXN],p[MAXN],fp[MAXN],cnt; void dfs2(int v,int td){ p[v]=++cnt;fp[cnt]=v;tp[v]=td; if(son[v]!=-1) dfs2(son[v],td); for(int i=0;i<vec[v].size();i++){ int u=vec[v][i]; if(u!=fa[v]&&u!=son[v]) dfs2(u,u); } } int d[MAXN]; int get_id(int x){ return x&(-x); } void add(int x){ for(int i=x;i<=n;i+=get_id(i)) d[i]++; } int querty(int x){ int ans=0; for(int i=x;i>0;i-=get_id(i)) ans+=d[i]; return ans; } typedef struct node{ int u,v,id,p; friend bool operator<(node aa,node bb){ return aa.p<bb.p; } }node; int get1(int u,int v){ int uu=tp[u];int vv=tp[v]; int ans=0; while(uu!=vv){ if(dep[uu]<dep[vv]) swap(uu,vv),swap(u,v); ans+=(p[u]-p[uu]+1); u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v]) swap(u,v); ans+=(p[v]-p[u]+1); return ans; } int get2(int u,int v){ int uu=tp[u];int vv=tp[v]; int ans=0; while(uu!=vv){ if(dep[uu]<dep[vv]) swap(uu,vv),swap(u,v); ans+=(querty(p[u])-querty(p[uu]-1)); u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v]) swap(u,v); ans+=(querty(p[v])-querty(p[u]-1)); return ans; } node que[MAXN]; bool pd[MAXN]; pii ans1[MAXN]; int vis[MAXN]; int main(){ scanf("%d",&n);int rt; int t; for(int i=1;i<=n;i++){ scanf("%d",&t);son[i]=-1; if(t==0){ rt=i;continue; } vec[i].push_back(t); vec[t].push_back(i); }cnt=0; int cnt1=0; dfs1(rt,0,0);dfs2(rt,rt); scanf("%d",&q); int op,u,v,c; for(int i=1;i<=q;i++){ scanf("%d",&op); if(op==1){ scanf("%d%d%d",&u,&v,&c); ans1[i].f=get1(u,v); que[++cnt1].u=u;que[cnt1].v=v;que[cnt1].p=max(0,i-c-1);que[cnt1].id=i; } else{ scanf("%d",&u); if(pd[u]) continue; vis[i]=u;pd[u]=1; } } sort(que+1,que+cnt1+1); int _=1; for(int i=0;i<=q;i++){ if(vis[i]) add(p[vis[i]]); for(;_<=cnt1&&que[_].p==i;_++){ ans1[que[_].id].s=get2(que[_].u,que[_].v); } } // if(_<=cnt1){ // for(;_<=cnt1;_++){ // ans1[que[_].id].s=get2(que[_].u,que[_].v); // } // } for(int i=1;i<=q;i++)if(!vis[i]) printf("%d %d ",ans1[i].f,ans1[i].s); return 0; }
loj 558
题意:有一个森林 初始时刻每个点都是白色的 现在有四种操作
1.对于u颜色反转
2.连接u,v
3.断开u,v
4.查询与u联通的所有黑点到u的距离的和
题解:大概很巧妙的是LCT维护子树信息 然后维护LCT维护当前节点的这段链上的贡献 注意反转的时候交换就行了 (但是这个题很毒 指针版本的LCT会A掉 然而数组版本的会T 虽然数组版本的没有A掉 就当作练习了
#include <cctype> #include <cstdio> #include <cstring> #include <algorithm> #define pii pair<int,int> #define il inline #define f first #define s second #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,l,r) for(int i=l;i>=r;i--) #define ll long long #define rg register const int MAXN=5e5+10; using namespace std; il int read() { rg int x=0,f=1; rg char ch=getchar(); while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*f; } int ch[MAXN][2],cnt,res[MAXN],pre[MAXN],st[MAXN],tp; ll sum[MAXN],chsum[MAXN],ke[MAXN],rsum[MAXN],num[MAXN],chnum[MAXN],vul[MAXN],size[MAXN]; bool rt[MAXN],key[MAXN]; il void reverse(int r) { if(!r) return ; std::swap(ch[r][0],ch[r][1]); std::swap(sum[r],rsum[r]); res[r]^=1; } il void push(int x) { if(res[x]) { reverse(ch[x][0]); reverse(ch[x][1]); res[x]=0; } } il void up(int x) { if(!x) return ; size[x]=size[ch[x][0]]+size[ch[x][1]]+1; num[x]=num[ch[x][0]]+num[ch[x][1]]+chnum[x]+key[x]; vul[x]=vul[ch[x][0]]+vul[ch[x][1]]+ke[x]; rsum[x]=rsum[ch[x][0]]+rsum[ch[x][1]]+chsum[x]+1ll*(vul[ch[x][1]]+ke[x])*(num[ch[x][0]]+chnum[x]+key[x]); sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+chsum[x]+1ll*(vul[ch[x][0]]+ke[x])*(num[ch[x][1]]+chnum[x]+key[x]); } il void P(int x) { rg int i; st[++tp]=x; for(i=x; !rt[i]; i=pre[i]) st[++tp]=pre[i]; for(; tp; tp--) push(st[tp]); } il void rotate(int x,int kind) { rg int y=pre[x]; ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if(rt[y]) rt[x]=1,rt[y]=0; else ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; up(y); } il void splay(int x) { P(x); while(!rt[x]) { if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x); else { rg int y=pre[x]; rg int kind=ch[pre[y]][0]==y; if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } up(x); } il void access(int x) { rg int y=0; while(x) { splay(x); if(ch[x][1]) { rt[ch[x][1]]=1; pre[ch[x][1]]=x; chsum[x]+=sum[ch[x][1]]; chnum[x]+=num[ch[x][1]]; } if(y) rt[y]=0,chsum[x]-=sum[y],chnum[x]-=num[y]; ch[x][1]=y; up(x); y=x; x=pre[x]; } } il void mroot(int u) { access(u); splay(u); reverse(u); } il void Link(int u,int v) { mroot(u); mroot(v); pre[u]=v; chnum[v]+=num[u]; chsum[v]+=sum[u]; up(v); } il void destory(int u,int v) { //if(!pd(u,v)) return ; mroot(u); access(v); splay(u); pre[v]=0;rt[v]=1; ch[u][1]=0;up(u); //up(x); } int main() { //freopen("1.in","r",stdin); //freopen("2.out","w",stdout); int n,m,k; n=read(); m=read(); k=read(); cnt=0; tp=0; inc(i,1,n) size[++cnt]=1,rt[cnt]=1; int u,v,w; while(m--) { u=read(); v=read(); w=read(); size[++cnt]=1,rt[cnt]=1; ke[cnt]=vul[cnt]=w; Link(u,cnt); Link(v,cnt); } char str[5]; while(k--) { scanf("%s",str); if(str[0]=='L') { u=read(),v=read(),w=read(),size[++cnt]=1,rt[cnt]=1; ke[cnt]=vul[cnt]=w; Link(u,cnt),Link(v,cnt); } else if(str[0]=='C') { u=read(); v=read(); destory(u,v); } else if(str[0]=='F') u=read(),mroot(u),key[u]^=1,up(u); else u=read(),mroot(u),printf("%lld ",sum[u]); } return 0; }