日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[luogu2664]树上游戏

發布時間:2024/4/11 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [luogu2664]树上游戏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

點分治

題目相關

鏈接

題目大意

給出一棵樹,每個節點有一個顏色
s(u,v)s(u,v)s(u,v)為樹上點uuu到點vvv的路徑上的顏色數
對于每個iii,求Si=∑j=1ns(i,j)S_i=\sum_{j=1}^ns(i,j)Si?=j=1n?s(i,j)

數據范圍

n≤100000n\le100000n100000

題解

點分治大法好(但是我們這里不考慮)
考慮每種顏色的貢獻
我們對于一種顏色把所有點拿出來
我們發現這些點將整棵樹切成了若干聯通塊(即不是這個顏色的點的聯通快)
我們發現對于在同一塊內的兩個點為端點的路徑是不包含這種顏色的,其它路徑都包含
那么我們現在考慮用所有的邊的方案減去不要求的方案
我們發現我們可以直接維護當前子樹內每種顏色的邊界節點,并用樹上差分維護答案的區間減
最后dfs一遍下傳差分標記即可
容易發現這些邊界節點會被加入一次再刪除一次
故總復雜度O(n)\mathcal O(n)O(n)

代碼

#include<cstdio> #include<cctype> #include<algorithm> #include<vector> namespace fast_IO {const int IN_LEN=1000000,OUT_LEN=1000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);} } using namespace fast_IO; #define getchar() getchar_() #define putchar(x) putchar_((x)) #define rg register typedef long long ll; template <typename T> inline T max(const T a,const T b){return a>b?a:b;} template <typename T> inline T min(const T a,const T b){return a<b?a:b;} template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;} template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;} template <typename T> inline T abs(const T a){return a>0?a:-a;} template <typename T> inline void Swap(T&a,T&b){T c=a;a=b;b=c;} //template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;} template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);} template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;} template <typename T> inline T square(const T x){return x*x;}; template <typename T> inline void read(T&x) {char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } template <typename T> inline void printe(const T x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } template <typename T> inline void print(const T x) {if(x<0)putchar('-'),printe(-x);else printe(x); } const int maxn=100005,maxm=200005; int n,c[maxn]; int head[maxn],nxt[maxm],tow[maxm],tmp; inline void addb(const int u,const int v) {tmp++;nxt[tmp]=head[u];head[u]=tmp;tow[tmp]=v; } int size[maxn]; ll ans[maxn]; std::vector<int>col[maxn]; void dfs(const int u,const int fa) {std::vector<int>&me=col[c[u]];const int SZ=me.size();size[u]=1;for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(v==fa)continue;dfs(v,u),size[u]+=size[v];if(u==0){for(c[u]=1;c[u]<=100000;c[u]++){std::vector<int>&M=col[c[u]];int dq=size[v];for(int i=M.size()-1;i>=SZ;i--)dq-=size[M[i]];ans[v]-=dq;for(int i=M.size()-1;i>=SZ;i--)ans[M[i]]+=dq;while(M.size()>0)M.pop_back();}continue;}int dq=size[v];for(int i=me.size()-1;i>=SZ;i--)dq-=size[me[i]];ans[v]-=dq;for(int i=me.size()-1;i>=SZ;i--)ans[me[i]]+=dq;while(me.size()>SZ)me.pop_back();}me.push_back(u); } void cf(const int u,const int fa) {for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(v==fa)continue;ans[v]+=ans[u],cf(v,u);} } int main() {read(n);for(rg int i=1;i<=n;i++)read(c[i]);addb(0,1),addb(1,0);for(rg int i=1;i<n;i++){int u,v;read(u),read(v);addb(u,v),addb(v,u);}dfs(0,0);cf(0,0);for(rg int i=1;i<=n;i++)print(ans[i]+(ll)n*100000),putchar('\n');return flush(),0; }

總結

點分好難,還是差分清真

總結

以上是生活随笔為你收集整理的[luogu2664]树上游戏的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。