BZOJ_3653_談笑風生_樹狀數組
阿新 • • 發佈:2018-04-29
AS 之間 接下來 pan bool while fix clas 除了
第一行含有兩個正整數n和q,分別代表有根樹的點數與詢問的個數。
接下來n - 1行,每行描述一條樹上的邊。每行含有兩個整數u和v,代表在節點u和v之間有一條邊。
接下來q行,每行描述一個操作。第i行含有兩個整數,分別表示第i個詢問的p和k。
1<=P<=N
1<=K<=N
N<=300000
Q<=300000
1 2
1 3
2 4
4 5
2 2
4 1
2 3
1
3
b有位置兩種可能,a的祖先和a的子樹。 如果b是a的祖先,則c只能選擇a子樹中除了a的一個。 如果b是a的子樹中的一個點,c只能選擇b子樹除了b的一個。 於是問題轉化為子樹裏距離小於等於k的子樹大小和。 兩個限制條件:子樹內和深度小於等於一個值。 把每個點的dfs序位置和深度看成兩個坐標,轉化為二維數點,同樹狀數組解決。 代碼:
BZOJ_3653_談笑風生_樹狀數組
Description
設T 為一棵有根樹,我們做如下的定義: ? 設a和b為T 中的兩個不同節點。如果a是b的祖先,那麽稱“a比b不知道 高明到哪裏去了”。 ? 設a 和 b 為 T 中的兩個不同節點。如果 a 與 b 在樹上的距離不超過某個給定 常數x,那麽稱“a 與b 談笑風生”。 給定一棵n個節點的有根樹T,節點的編號為1 到 n,根節點為1號節點。你需 要回答q 個詢問,詢問給定兩個整數p和k,問有多少個有序三元組(a;b;c)滿足: 1. a、b和 c為 T 中三個不同的點,且 a為p 號節點; 2. a和b 都比 c不知道高明到哪裏去了; 3. a和b 談笑風生。這裏談笑風生中的常數為給定的 k。Input
Output
輸出 q 行,每行對應一個詢問,代表詢問的答案。
Sample Input
5 31 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
31
3
b有位置兩種可能,a的祖先和a的子樹。 如果b是a的祖先,則c只能選擇a子樹中除了a的一個。 如果b是a的子樹中的一個點,c只能選擇b子樹除了b的一個。 於是問題轉化為子樹裏距離小於等於k的子樹大小和。 兩個限制條件:子樹內和深度小於等於一個值。 把每個點的dfs序位置和深度看成兩個坐標,轉化為二維數點,同樹狀數組解決。 代碼:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 300050 typedef long long ll; int head[N],to[N<<1],nxt[N<<1],cnt,n,m; int dep[N],siz[N],dfn[N],S[N],son[N]; ll c[N],ans[N]; inline void add(int u,int v) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; } void fix(int x,int v) { for(;x<=n;x+=x&(-x)) c[x]+=v; } ll inq(int x) { ll re=0; for(;x;x-=x&(-x)) re+=c[x]; return re; } struct QAQ { int p,d,id,opt; }a[N<<1]; bool cmp(const QAQ &x,const QAQ &y) { if(x.p==y.p) return x.opt<y.opt; return x.p<y.p; } void dfs(int x,int y) { int i; S[++S[0]]=x; dfn[x]=S[0]; dep[x]=dep[y]+1; siz[x]=1; for(i=head[x];i;i=nxt[i]) if(to[i]!=y) { dfs(to[i],x); siz[x]+=siz[to[i]]; } son[x]=S[0]; } int main() { scanf("%d%d",&n,&m); int i,x,y; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); int tot=0; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); ans[i]=1ll*min(y,dep[x]-1)*(siz[x]-1); int depp=min(dep[x]+y,n); a[++tot].p=dfn[x]; a[tot].opt=-1; a[tot].d=depp; a[tot].id=i; a[++tot].p=son[x]; a[tot].opt=1; a[tot].d=depp; a[tot].id=i; } sort(a+1,a+tot+1,cmp); int now=0; for(i=1;i<=tot;i++) { while(now<=n&&now<a[i].p) now++,fix(dep[S[now]],siz[S[now]]-1); ans[a[i].id]+=a[i].opt*inq(a[i].d); } for(i=1;i<=m;i++) printf("%lld\n",ans[i]); }
BZOJ_3653_談笑風生_樹狀數組