題面挺神仙。反正我考試的時候看了40分鐘也沒看懂。
後來改題感覺自己寫的挺假,沒想到加個\(k==1\)的特判竟然就a了?無語力。
看懂題以後就好說了。首先這顯然是乙個樹形結構。我們考慮把「交」的操作放到一棵樹上,把「並」的操作放到一棵樹上。
考慮建邊。比如將\((1,2,3)\)並成\((4)\),那麼就在並樹上,將\(1,2,3\)的父親設定成\(4\)。
然後,對於每個詢問\((x,y)\),如果在交樹上,\(x\)是\(y\)的祖先,或在並樹上,\(y\)是\(x\)的祖先,那麼答案就是\(1\),否則是\(0\)。
看起來有手就行。不過細節還是要注意。
我們在建立模型的時候,顯然建的是有向邊,由兒子指向父親。但我們在真正建樹的時候,是要建無向邊。因為無向邊比較好維護。那此時怎麼判斷父子關係呢?
首先,有乙個性質。每個節點的父親的編號一定比自己的編號大。也就是說,大的點一定在上面。因為維護的是一片森林,所以可以根據這個性質找到每棵樹的根節點。
所以可以考慮按編號從大到小dfs一遍。按照dfs序判斷父子關係。
寫過樹剖的人都知道,一顆子樹內的dfs序是連續的。因此假如y是x的父親,那麼\(dfn[y]<=dfn[x]<=dfn[x]+size[x]-1<=dfn[y]+size[y]-1\)
注意乙個細節。\(k==1\)的時候,交和並等價。那麼既要在交樹上建邊,又要在並樹上建邊。
然後就可以a掉這道題了。
首先,對於在y到根節點上的路徑上的點(不包括根節點),那麼這些節點既有入度,也有出度,那麼這些點就不可能在另外一棵樹上出現了。
其次,對於根節點,它只可能去合成別的節點,那麼它在另一棵樹上一定沒有入度。也就是說,即使根節點在另一棵樹上出現,它也必然是葉子節點,不可能是x的父親,所以不用判。
**:
#include using namespace std;
const int maxn=500000+10;
int n,m,cntj,cntb,totot,totj,totb,time;
struct nodeedgej[maxn],edgeb[maxn];
int headj[maxn],headb[maxn],dfnb[maxn],dfnj[maxn],sizeb[maxn],sizej[maxn];
struct queb[maxn];
bool vis[maxn];
void addj(int from,int to)
void addb(int from,int to)
void dfs1(int u,int f)
}void dfs2(int u,int f)
}int get_ans(int x,int y)
void solve()else
}else
}}else
}else}}
} }//printf("n==%d totj=%d totb=%d cntj==%d cntb==%d\n",n,totj,totb,cntj,cntb);
for(int i=totj+totb+n;i;--i) if(!vis[i]) dfs1(i,0);
memset(vis,0,sizeof(vis));
time=0;
for(int i=totb+totj+n;i;--i) if(!vis[i]) dfs2(i,0);
//for(int i=1;i<=totj+totb+n;++i) printf("dfnj[%d]=%d dfnb[%d]=%d sizej[%d]=%d sizeb[%d]=%d\n",i,dfnj[i],i,dfnb[i],i,sizej[i],i,sizeb[i]);
for(int i=1;i<=totot;++i) printf("%d\n",get_ans(b[i].x,b[i].y));
}int main()
驚奇建模《主僕見證了 Hobo 的離別》
1 新元件的編號等於融合之前元件的總個數加一。當然,參與融合的 k個元件融合之後依然存在,並且每個元件至多參與一次融合。2由於元件的容量有限,eddie 沒有能力喚醒 hobo 全部的回憶,所以他會用下列兩種方式來融合元件 34 集合的交 一段記憶儲存在新的元件中,當且僅當這段記憶在參與融合的k 個...
一場雨我們的見證了什麼?
2012年7月21日晚,一場大雨突襲北京及其周邊地區,此時我所在的地方是廊坊,每天還照常一樣,晚上9點半之後離開機房,走在回寢室的路上。路上的積水很多,我和幾個姐妹相互伴同著,淌水走在積水已經很深的路上,路已然很黑,61年不遇的大雨讓道路更加打滑,其中乙個小師妹因為鞋子打滑不得不脫了光腳走回了寢室 ...