【BZOJ】【3653】谈笑风生
2015-04-18 23:38
423 查看
dfs序+可持久化线段树
好吧……是我too naive这题……$$ans=min(dep[x],k)×(size[x]-1)+\sum_{y在x的子树中,且dis(x,y)<=k}(size[y]-1)$$
那么重点是后面sigma的部分,这里看到子树中信息的统计可以用dfs序……但是对子树中dep在某个范围内的点的size求和?
我们可以用权值线段树呀~dep做关键字,size的和是线段树上统计的额外信息,那么对整个dfs序做可持久化线段树就可以了……查询的时候就像普通线段树一样。
调了很久的一个地方……
F(i,1,n) update(root[i]=root[i-1],0,n,dep[a[i]],sz[a[i]]-1);
这一句中我一开始写成.......dep[a[x]],sz[a[x]]-1了!!
因为在dfs的过程中我是用x这个变量来表示某个节点的……然后这里顺着思路就写下来了……
你可能会说,为什么没有CE呢?那是因为我在读入边的时候声明了两个变量x,y……看代码上下文就知道了TAT
/************************************************************** Problem: 3653 User: Tunix Language: C++ Result: Accepted Time:8964 ms Memory:158752 kb ****************************************************************/ //Huce #1 D #include<vector> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define rep(i,n) for(int i=0;i<n;++i) #define F(i,j,n) for(int i=j;i<=n;++i) #define D(i,j,n) for(int i=j;i>=n;--i) #define pb push_back using namespace std; inline int getint(){ int v=0,sign=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} return v*sign; } const int N=3e5+10,INF=~0u>>2; typedef long long LL; /******************tamplate*********************/ int head ,to[N<<1],next[N<<1],cnt; void add(int x,int y){ to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; } int n,m,a ,dep ,sz ,st ,ed ,root ,tot,ct; struct Tree{ int l,r; LL sum; }t[N*30]; #define mid (l+r>>1) void update(int &o,int l,int r,int pos,int w){ t[++ct]=t[o], o=ct, t[o].sum+=w; if (l==r) return; if (pos<=mid) update(t[o].l,l,mid,pos,w); else update(t[o].r,mid+1,r,pos,w); } LL query(int i,int j,int l,int r,int ql,int qr){ if (ql<=l && qr>=r){ return t[j].sum-t[i].sum; }else{ LL ans=0; if (ql<=mid) ans+=query(t[i].l,t[j].l,l,mid,ql,qr); if (qr> mid) ans+=query(t[i].r,t[j].r,mid+1,r,ql,qr); return ans; } } #undef mid void dfs(int x){ a[st[x]=++tot]=x; sz[x]=1; for(int i=head[x];i;i=next[i]) if (st[to[i]]==0){ dep[to[i]]=dep[x]+1; dfs(to[i]); sz[x]+=sz[to[i]]; } ed[x]=tot; } int main(){ #ifndef ONLINE_JUDGE freopen("D.in","r",stdin); freopen("D.out","w",stdout); #endif n=getint(); m=getint(); int x,y; F(i,2,n){ x=getint(); y=getint(); add(x,y); } dfs(1); F(i,1,n) update(root[i]=root[i-1],0,n,dep[a[i]],sz[a[i]]-1); F(i,1,m){ x=getint(); y=getint(); LL ans=(LL)(sz[x]-1)*min(dep[x],y); ans+=query(root[st[x]-1],root[ed[x]],0,n, dep[x]+1,min(dep[x]+y,n)); printf("%lld\n",ans); } return 0; }
View Code
3653: 谈笑风生
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 225 Solved: 79
[Submit][Status][Discuss]
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
输入文件的第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。接下来n - 1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。接下来q行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。
Output
输出 q 行,每行对应一个询问,代表询问的答案。Sample Input
5 31 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
31
3
HINT
1<=P<=N1<=K<=N
N<=300000
Q<=300000
Source
[Submit][Status][Discuss]相关文章推荐
- 【BZOJ3653】谈笑风生【主席树】【DFS序】
- [bzoj3653]谈笑风生 主席树
- bzoj 3653: 谈笑风生 可持久化线段树
- 【bzoj3653】谈笑风生 DFS序+树状数组
- BZOJ3653 : 谈笑风生
- 【BZOJ 3653】 谈笑风生|主席树
- BZOJ3653: 谈笑风生
- BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)
- 【主席树】bzoj3653 谈笑风生
- Bzoj3653 谈笑风生
- bzoj 3653 [湖南集训]谈笑风生
- BZOJ 3653 谈笑风生
- BZOJ_3653_谈笑风生_树状数组
- 【bzoj3653】【谈笑风生】【dfs序+主席树】
- BZOJ3653 & 洛谷3899:谈笑风生——题解
- BZOJ3653 谈笑风生
- bzoj 3653: 谈笑风生
- BZOJ3653: 谈笑风生
- bzoj3653: 谈笑风生
- 【bzoj3653】谈笑风生