test20181004 蘋果樹
阿新 • • 發佈:2018-10-04
for fir semi date namespace 兩種 通過 != cstring
題意
分析
對每個點維護子樹所能達到的dfn最大值、最小值、次大值、次小值,然後就可以計算原樹中每個點與父親的連邊對答案的貢獻。
- 如果子樹中沒有邊能脫離子樹,斷掉該邊與任意一條新加的邊都成立,答案就加m。
- 如果子樹中只有1條邊能脫離子樹,只能斷掉該邊和那條能脫離子樹的邊,答案就加1。
- 如果子樹中有大於等於2條邊能脫離子樹,那麽不能通過斷邊使子樹獨立,答案不變。
代碼
#include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<ctime> #include<iostream> #include<string> #include<vector> #include<list> #include<deque> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> #include<algorithm> #include<complex> #pragma GCC optimize ("O0") using namespace std; template<class T> inline T read(T&x) { T data=0; int w=1; char ch=getchar(); while(!isdigit(ch)) { if(ch==‘-‘) w=-1; ch=getchar(); } while(isdigit(ch)) data=10*data+ch-‘0‘,ch=getchar(); return x=data*w; } typedef long long ll; const int INF=0x7fffffff; const int MAXN=3e5+7; int n,m; struct Edge { int nx,to; }E[MAXN<<2]; int head[MAXN],ecnt; void addedge(int x,int y) { E[++ecnt].to=y; E[ecnt].nx=head[x],head[x]=ecnt; } int fa[MAXN],siz[MAXN]; int dfn[MAXN],clk; void dfs1(int x,int f) { fa[x]=f,siz[x]=1; dfn[x]=++clk; for(int i=head[x];i;i=E[i].nx) { int y=E[i].to; if(y==f) continue; dfs1(y,x); siz[x]+=siz[y]; } } int minv[MAXN],semi[MAXN]; int maxv[MAXN],semx[MAXN]; ll ans; void dfs2(int x) { for(int i=head[x];i;i=E[i].nx) { int y=E[i].to; if(y==fa[x]) continue; dfs2(y); semi[x]=min(semi[x],max(minv[x],minv[y])); semi[x]=min(semi[x],semi[y]); minv[x]=min(minv[x],minv[y]); semx[x]=max(semx[x],min(maxv[x],maxv[y])); semx[x]=max(semx[x],semx[y]); maxv[x]=max(maxv[x],maxv[y]); } int out=(minv[x]<dfn[x])+(semi[x]<dfn[x])*10+ (maxv[x]>dfn[x]+siz[x]-1)+(semx[x]>dfn[x]+siz[x]-1)*10; /* cerr<<"check "<<x<<endl; cerr<<" minv="<<minv[x]<<" semi="<<semi[x]<<endl; cerr<<" maxv="<<maxv[x]<<" semx="<<semx[x]<<endl; cerr<<" ans="<<((out==0)*m+(out==1)*1)<<endl;*/ if(x!=1) ans+=(out==0)*m+(out==1)*1; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); read(n);read(m); for(int i=1;i<n;++i) { static int x,y; read(x);read(y); addedge(x,y); addedge(y,x); } dfs1(1,0); for(int i=1;i<=n;++i) { // cerr<<"dfn["<<i<<"]="<<dfn[i]<<endl; minv[i]=maxv[i]=semi[i]=semx[i]=dfn[i]; } for(int i=1;i<=m;++i) { static int x,y; read(x);read(y); if(dfn[x]>dfn[y]) swap(x,y); if(dfn[x]<semi[y]) // edit 1:The first and the second must be updated like this. { semi[y]=dfn[x]; if(semi[y]<minv[y]) swap(semi[y],minv[y]); } if(dfn[y]>semx[x]) { semx[x]=dfn[y]; if(semx[x]>maxv[x]) swap(semx[x],maxv[x]); } } dfs2(1); printf("%lld",ans); // fclose(stdin); // fclose(stdout); return 0; }
Hint
更新最大最小值以及次大次小值的時候,分為兩種情況。
- 子樹中的合並,就用吉司機線段樹那種合並方式。
- 新增邊時候的修改,必須用swap形式的方式修改。
有同學寫vector存圖被卡了,另外我的代碼最慢測試點只跑了0.2s,以後要借鑒這種常數小的寫法。
test20181004 蘋果樹