bzoj4835 遺忘之樹

2021-08-01 09:01:24 字數 1793 閱讀 6870

定義任意兩點之間存在唯一路徑的無向圖是樹。對於一棵n個點的樹,如果刪掉某個點u之後每個連通塊的大小均不

超過n/2,那麼稱u為這棵樹的重心。現在有一棵n個點的樹t,利用過程p來構造乙個n個點的有向圖g,初始g沒有邊

。現在對t呼叫過程p,p的內容如下:

1:刪去u,對每個連通塊遞迴呼叫過程p;

2:對每個連通塊,如果它的標號最小的重心為v,那麼在圖g中連一條u到v的有向邊。

3:現在小q同學手裡有乙個圖g,但是不記得原來t的樣子了,希望你能通過g來恢復t,但是可能得到的t會有很多種

你只需要告訴小q同學可能的t的個數。

兩棵樹被認為是不同的,當且僅當存在一對點(u,v),使得u和v在一棵樹中有邊,在另一棵樹中沒有邊。

設f[i]表示以點分樹中i為根有多少種原樹。

對於i的兒子j,如果size[j]不是size[i]的一半,直接f[i]*=f[j]*size[j]。

否則,按照題目的定義,只能選取編號大的,我們找到j子樹中所有編號大於i的,設個數為k,則f[i]*=f[j]*k。

可以用線段樹合併,也可以暴力。暴力的複雜度是對的是因為顯然最壞情況是滿二叉樹,此時複雜度是n log n。

#include

#include

#include

#define fo(i,a,b) for(i=a;i<=b;i++)

using namespace std;

typedef long long ll;

const int maxn=100000+10,maxtot=2000000+10,mo=1000000007;

ll f[maxn];

int tree[maxtot],left[maxtot],right[maxtot],root[maxn];

int size[maxn],h[maxn],go[maxn],next[maxn],d[maxn];

int i,j,k,l,t,n,m,tot,ca,ans,wdc;

void add(int

x,int

y)int newnode(int

x)void insert(int &x,int l,int r,int a)

int mid=(l+r)/2;

if (a<=mid) insert(left[x],l,mid,a);else insert(right[x],mid+1,r,a);

tree[x]=tree[left[x]]+tree[right[x]];

}int query(int

x,int l,int r,int a,int b)

int merge(int a,int b,int l,int r)

int mid=(l+r)/2;

left[a]=merge(left[a],left[b],l,mid);

right[a]=merge(right[a],right[b],mid+1,r);

tree[a]=tree[left[a]]+tree[right[a]];

return a;

}void dfs(int

x) t=h[x];

while (t)

insert(root[x],1,n,x);

}int main()

fo(i,1,n)

if (!d[i])

tot=0;

dfs(wdc);

ans=f[wdc];

(ans+=mo)%=mo;

printf("%d\n",ans);

}}

BZOJ 1012之線段樹解法

根據題意,很容易想到線段樹,單點修改,區間查詢,線段樹的模板大家都有,所以就不再做過多解釋。不過有一點值得一提,在我做這道題的時候使用了cin和cout,後來隊友告訴我,bzoj使用了o2優化,使用cin和cout可能會報錯,果然,我改了cin和cout之後就沒有問題了。include includ...

bzoj 3689 異或之 字典樹 堆

給定n個非負整數a 1 a 2 a n 對於每對 i,j 滿足1 i j n,得到乙個新的數a i xor a j 這樣共有n n 1 2個新的數。求這些數 不包含a i 中前k小的數。2 n 100000 1 k min 0 a i 2 31 先對所有數建一棵字典樹,對字典樹的每個節點記錄這個節點...

BZOJ 3689 異或之 Trie樹 堆

題目鏈結 description 給定n個非負整數a 1 a 2 a n 對於每對 i,j 滿足1 i j n,得到乙個新的數a i xor a j 這樣共有n n 1 2個新的數。求這些數 不包含a i 中前k小的數。注 xor對應於pascal中的 xor c 中的 input 第一行2個正整數...