1. 程式人生 > 實用技巧 >ybtoj 樹上取模

ybtoj 樹上取模

  • 看到這種需要對樹上以及子樹區間內部的樹進行操作的題目,想都不用想就是樹鏈剖分了
  • 打模板已經熟悉到爆炸了,關鍵是怎麼樣在已知條件下引入新的操作
  • 觀察到新操作只有一個:取mod,怎麼解決呢?
  • 這一題我們得出了兩個經驗
  1. 在空間允許的範圍以內,一顆線段樹上面可以搭載多條資訊
  2. 對於節點的操作我們要注意轉化成id[x]
  3. 化簡的關鍵在與去除冗餘計算
  • 思考取mod什麼時候是冗餘的
  1. 如果說一個數小於mod,那麼他就不用被取mod
  2. 線段樹可以儲存的資訊是區間可以進行合併的(比如眾數就不行)
  • 根據上述兩個事實,我們可以得出結論:儲存區間最大值(因為很可能發生多次取mod來卡常數)
  • 由此就對應出來的就是pushup的寫法就好
  • 最後注意輸入輸出:想一想一個n-1和m你找了有多久
  • 程式碼如下:
  • #include <stdio.h>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    #define lson k << 1
    #define rson k << 1 | 1
    
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+5;
    
    int head[maxn],nex[maxn<<1],ver[maxn<<1
    ],tot; int dep[maxn],sz[maxn],son[maxn],fa[maxn],rev[maxn],id[maxn],top[maxn],idx; int maxx[maxn<<2]; int a[maxn]; ll s[maxn<<2]; int n,m; inline int read() { int x=0; char ch=getchar(); while(ch<48||ch>57) ch=getchar(); while(ch>=48&&ch<=57) x=x*10+ch-48
    ,ch=getchar(); return x; } inline void add(int x,int y) { ver[++tot]=y; nex[tot]=head[x]; head[x]=tot; } inline void dfs(int x,int f) { dep[x]=dep[f]+1;fa[x]=f;sz[x]=1; for(int i=head[x];i;i=nex[i]) { int y=ver[i]; if(y==f) continue ; dfs(y,x); sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; } } inline void dfs2(int x,int t) { id[x]=++idx;top[x]=t;rev[id[x]]=a[x]; if(!son[x]) return ; dfs2(son[x],t); for(int i=head[x];i;i=nex[i]) { int y=ver[i]; if(y!=fa[x]&&y!=son[x]) dfs2(y,y); } } inline void pushup(int k) { //printf("##%d %d %d \n",k,lson,rson); s[k]=s[lson]+s[rson]; maxx[k]=maxx[lson]>maxx[rson]?maxx[lson]:maxx[rson]; } inline void build(int k,int l,int r) { if(l==r) { s[k]=maxx[k]=rev[l]; return; } int mid=l+r>>1; build(lson,l,mid); build(rson,mid+1,r); pushup(k); } inline void change(int k,int l,int r,int x,int v) { if(l==r) { s[k]=maxx[k]=v; return; } int mid=l+r>>1;// if(x<=mid) change(lson,l,mid,x,v); else change(rson,mid+1,r,x,v); pushup(k); } inline void change_mod(int k,int l,int r,int x,int y,int q) { if(maxx[k]<q) return; if(l==r)// { s[k]%=q; maxx[k]=s[k]; return; } int mid=l+r>>1; if(x<=mid) change_mod(lson,l,mid,x,y,q); if(mid<y) change_mod(rson,mid+1,r,x,y,q);// pushup(k); } inline ll query(int k,int l,int r,int x,int y) { if(l>y||r<x||l>r) return 0;// if(l>=x&&r<=y) return s[k]; int mid=l+r>>1; ll ans=0;// if(mid>=x) ans+=query(lson,l,mid,x,y); if(mid<y) ans+=query(rson,mid+1,r,x,y); return ans; } inline ll ask(int x,int y) { ll res=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); res+=query(1,1,n,id[top[x]],id[x]); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); res+=query(1,1,n,id[x],id[y]); return res; } int main() { freopen("flower.in","r",stdin); freopen("flower.out","w",stdout); // scanf("%d%d",&n,&m); n=read();m=read(); //printf("%d",n); for(int i=1;i<=n-1;i++) { int x,y; // scanf("%d%d",&x,&y); x=read();y=read(); add(x,y); add(y,x); } for(int i=1;i<=n;i++) a[i]=read();//scanf("%d",&a[i]); dfs(1,0); dfs2(1,1); build(1,1,n); for(int i=1,op,a1,a2;i<=m;i++) { op=read(); //printf("!%d\n",op); a1=read(); a2=read(); //scanf("%d%d%d",&op,&x,&y); if(op==1) change_mod(1,1,n,id[a1],id[a1]+sz[a1]-1,a2); if(op==2) change(1,1,n,id[a1],a2); if(op==3) printf("%lld\n",ask(a1,a2)); } return 0; }