[USACO18JAN][luoguP4183 ]Cow at Large P
前言
這是一道考試題
需要一定的idea
構(gòu)造好后似乎就是裸的點分治了
題目相關(guān)
題目鏈接
題目大意
這個大意寫的很煩,不如看題面
有一棵nnn個點的樹
設(shè)定一個動點:其每秒可以走到樹上相鄰的一個節(jié)點,若當前它在一個度數(shù)為1的節(jié)點上,它可以逃出這棵樹
定義動點相遇為它們在節(jié)點上或邊上相遇
對于每個點,求現(xiàn)在在當前點上有個動點想要逃出這棵樹,你至少要在多少個葉子節(jié)點上放置防守動點才能保證它不會逃出去(如果防守動點碰到動點,那么那個動點就被抓住了)
數(shù)據(jù)范圍
n≤7?104n\le7*10^4n≤7?104
題解
我們可以通過Θ(n)\Theta(n)Θ(n)的樹形dp求出離iii點最近的葉子節(jié)點到iii點的距離gig_igi?
可能算上下dp
設(shè)iii號點的度數(shù)為did_idi?
我們發(fā)現(xiàn)對于di=1d_i=1di?=1的點答案一定為111(即放一個點在它自己上即可)
那么我們考慮如何統(tǒng)計di≠1d_i\neq1di???=1的點
對于每一個根(即選中的那個點),設(shè)depidep_idepi?為根到iii點的距離,faifa_ifai?為iii號點的父親
每當有一個節(jié)點iii滿足depi≥gidep_i\ge g_idepi?≥gi?并且depfai<gfaidep_{fa_i}<g_{fa_i}depfai??<gfai??,那么當前根的答案加一
然后這個統(tǒng)計大概是Θ(n2)\Theta(n^2)Θ(n2)的
然后考慮優(yōu)化
我們發(fā)現(xiàn)對于depi≥gidep_i\ge g_idepi?≥gi?的節(jié)點的存在都在聯(lián)通子樹中
每個聯(lián)通子樹貢獻111的答案(樹根貢獻)
如果我們可以快速計數(shù)就可以獲取答案
然后這個時候有一個很巧妙的構(gòu)造
考場上我并沒有想到這個
對于一個mmm個點的子樹,其邊數(shù)是m?1m-1m?1條
我們發(fā)現(xiàn)對于這個子樹∑di=2?(m?1)+1\sum d_i=2*(m-1)+1∑di?=2?(m?1)+1
我們又發(fā)現(xiàn)∑1=m\sum1=m∑1=m
所以∑di=2?(m?1)+1∑di=2?m?11=2?m?∑di1=∑(2?di)\begin{aligned} \sum d_i&=2*(m-1)+1\\ \sum d_i&=2*m-1\\ 1&=2*m-\sum d_i\\ 1&=\sum(2-d_i) \end{aligned}∑di?∑di?11?=2?(m?1)+1=2?m?1=2?m?∑di?=∑(2?di?)?
剛好符合我們想要的
所以我們現(xiàn)在要求的就是:∑i=1n[depi≥gi](2?di)\sum_{i=1}^n[dep_i\ge g_i](2-d_i)i=1∑n?[depi?≥gi?](2?di?)
我們發(fā)現(xiàn)∑i=1n(2?di)=∑i=1n2?∑i=1ndi=2?n?2?(n?1)=2\begin{aligned} \sum_{i=1}^n(2-d_i)&=\sum_{i=1}^n2-\sum_{i=1}^nd_i\\ &=2*n-2*(n-1)\\ &=2 \end{aligned}i=1∑n?(2?di?)?=i=1∑n?2?i=1∑n?di?=2?n?2?(n?1)=2?
然后我們要求的就成了2?∑i=1n[depi<gi](2?di)2-\sum_{i=1}^n[dep_i<g_i](2-d_i)2?i=1∑n?[depi?<gi?](2?di?)
設(shè)點uuu的答案為ansuans_uansu?
ansu=2?∑v=1n[dis(u,v)<gv](2?dv)ans_u=2-\sum_{v=1}^n[dis(u,v)<g_v](2-d_v)ansu?=2?v=1∑n?[dis(u,v)<gv?](2?dv?)
然后就可以使用點分治
我們點分的時候每次計算經(jīng)過當前分治重心的路徑點對(u,v)(u,v)(u,v)
設(shè)點iii與分治重心的距離為pip_ipi?
dis(u,v)=pu+pvdis(u,v)=p_u+p_vdis(u,v)=pu?+pv?
然后
dis(u,v)<gv?pu+pv<gv?pu<gv?pvdis(u,v)<g_v\Leftrightarrow p_u+p_v<g_v\Leftrightarrow p_u<g_v-p_vdis(u,v)<gv??pu?+pv?<gv??pu?<gv??pv?
用樹狀數(shù)組維護即可
復(fù)雜度Θ(nlog2n)\Theta(nlog^2n)Θ(nlog2n)
代碼
貼上AC代碼
#include<cstdio> #include<cctype> #include<cstring> #include<cmath> namespace fast_IO {const int IN_LEN=10000000,OUT_LEN=10000000;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)) typedef long long LL; #define rg register 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 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> 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=70001,maxm=140002,INF=0x7f7f7f7f; int n,d[maxn]; int head[maxn],nxt[maxm],tow[maxm],tmp=1; int fi[maxn]; inline void addb(const int u,const int v) {tmp++;nxt[tmp]=head[u];head[u]=tmp;tow[tmp]=v; } void dfs1(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;dfs1(v,u);mind(fi[u],fi[v]+1);}if(fi[u]==INF)fi[u]=0; } void dfs2(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;mind(fi[v],fi[u]+1);dfs2(v,u);} } bool Hash[maxn];int son[maxn],minn,root,size; int ans[maxn]; void getroot(const int u,const int fa) {son[u]=1;int maxx=0;for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(v==fa||Hash[v])continue;getroot(v,u);son[u]+=son[v];maxd(maxx,son[v]);}maxd(maxx,size-son[u]);if(maxx<minn)minn=maxx,root=u; } int Q[maxn],tot,dis[maxn]; void dfs(const int u,const int fa) {Q[++tot]=u; for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(v==fa||Hash[v])continue;dis[v]=dis[u]+1,dfs(v,u);} } int tree[maxn]; inline int lowbit(const int x){return x&-x;} inline void add(int whe,const int man) {while(whe<=n){tree[whe]+=man;whe+=lowbit(whe);} } inline int qz(int whe) {rg int res=0;while(whe){res+=tree[whe];whe^=lowbit(whe);}return res; } void calc(const int u,const int sign,const int G) {tot=0,dis[u]=G;dfs(u,u);for(rg int i=1;i<=tot;i++){const int v=Q[i];add(n-fi[v]+dis[v],2-d[v]);}for(rg int i=1;i<=tot;i++){const int v=Q[i];ans[v]+=sign*qz(n-dis[v]-1);}for(rg int i=1;i<=tot;i++){const int v=Q[i];add(n-fi[v]+dis[v],d[v]-2);} } void solve(const int u,const int SIZE,const int SON) {Hash[u]=1;calc(u,-1,0);for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(Hash[v])continue;calc(v,1,1);minn=INF,size=son[v];if(size>SON)size=SIZE-SON;getroot(v,u),solve(root,size,son[root]);} } int main() {memset(fi,0x7f,sizeof(fi));read(n);for(rg int i=1;i<n;i++){int u,v;read(u),read(v);addb(u,v),addb(v,u);d[u]++,d[v]++;}int RT=0;for(rg int i=1;i<=n;i++)if(d[i]>1)RT=i;dfs1(RT,RT);dfs2(RT,RT);for(rg int i=1;i<=n;i++)ans[i]=2;minn=INF,size=n,getroot(1,1),solve(root,size,son[root]);for(rg int i=1;i<=n;i++)print(d[i]==1?1:ans[i]),putchar('\n');return flush(),0; }總結(jié)
構(gòu)造很巧妙,一個很好的idea
然后點分治比較裸,很清真
總結(jié)
以上是生活随笔為你收集整理的[USACO18JAN][luoguP4183 ]Cow at Large P的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [HAOI2015][loj2127]按
- 下一篇: 分治FFT