bzoj 3653 谈笑风生——主席树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3653

原来一直想怎么线段树合并。可是不会把角标挪一位。

查询的其实是子树内一段深度的点的 siz 和。因为是子树内,所以按 dfs 序建立主席树,角标是 dep ,值是 siz 。

注意 long long 。而且数组 *19 就会 RE ,*20就好了。不知为何。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=3e5+5,M=N*20;
int n,Q,hd[N],xnt,to[N<<1],nxt[N<<1],siz[N],dfn[N],tim;
int tot,rt[N],ls[M],rs[M],dep[N];
ll sm[M];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=0;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘) ret=(ret<<3)+(ret<<1)+ch-‘0‘,ch=getchar();
  return fx?ret:-ret;
}
void write(ll x)
{
  if(x<0)putchar(‘-‘),x=-x;
  if(x<10){putchar(x+‘0‘);return;}
  write(x/10); putchar(x%10+‘0‘);
}
void add(int x,int y)
{
  to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;
}
void dfs(int cr,int fa)
{
  siz[cr]=1; dep[cr]=dep[fa]+1;
  for(int i=hd[cr],v;i;i=nxt[i])
    if((v=to[i])!=fa)dfs(v,cr),siz[cr]+=siz[v];
}
void mrg(int l,int r,int &cr,int pr,int p,int k)
{
  cr=++tot; sm[cr]=sm[pr]+k;
  if(l==r)return;  int mid=l+r>>1;
  ls[cr]=ls[pr]; rs[cr]=rs[pr];
  if(p<=mid)mrg(l,mid,ls[cr],ls[pr],p,k);
  else mrg(mid+1,r,rs[cr],rs[pr],p,k);
}
void dfsx(int cr,int fa)
{
  dfn[cr]=++tim; mrg(1,n,rt[dfn[cr]],rt[dfn[cr]-1],dep[cr],siz[cr]-1);
  for(int i=hd[cr],v;i;i=nxt[i])
    if((v=to[i])!=fa)dfsx(v,cr);
}
ll query(int l,int r,int cr,int pr,int L,int R)
{
  if(l>=L&&r<=R)return sm[cr]-sm[pr];
  int mid=l+r>>1; ll ret=0;
  if(L<=mid)ret=query(l,mid,ls[cr],ls[pr],L,R);
  if(mid<R)ret+=query(mid+1,r,rs[cr],rs[pr],L,R);
  return ret;
}
int main()
{
  n=rdn(); Q=rdn();
  for(int i=1,u,v;i<n;i++)
    {
      u=rdn(); v=rdn(); add(u,v); add(v,u);
    }
  dfs(1,0); dfsx(1,0);
  for(int i=1,p,k;i<=Q;i++)
    {
      p=rdn(); k=rdn();
      ll ans=(ll)min(k,dep[p]-1)*(siz[p]-1);
      if(siz[p]>1)
    ans+=query(1,n,rt[dfn[p]+siz[p]-1],rt[dfn[p]],dep[p]+1,dep[p]+k);
      write(ans); puts("");
    }
  return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/9868575.html

时间: 2024-12-12 07:39:11

bzoj 3653 谈笑风生——主席树的相关文章

bzoj 2653 middle (主席树+二分)

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 2653 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置也从0开始标号. 强制在线. 解法: 首先可以想到的是二分答案,再判断是否满足条件 . 对于答案x,我们将原数组中大于等于x的数记1,小于的记为-1,

[湖南集训] 谈笑风生 (主席树)

[湖南集训] 谈笑风生 题目描述 设 T 为一棵有根树,我们做如下的定义: ? 设 a 和 b 为 T 中的两个不同节点.如果 a 是 b 的祖先,那么称"a 比 b 不知道高明到哪里去了". ? 设 a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数 x,那么称"a 与 b 谈笑风生". 给定一棵 n 个节点的有根树 T,节点的编号为 1 - n,根节点为 1 号节点.你需要回答 q 个询问,询问给定两个整数 p 和 k,问有多

BZOJ 2735: 世博会 主席树+切比雪夫距离转曼哈顿距离

2735: 世博会 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 124  Solved: 51[Submit][Status][Discuss] Description 四年一度的世博会又要举办了,Q国很荣幸成为了这次世博会的主办方.Q国主席QQ从全国各地收集了N件物品排成 一排,作为Q国馆的展出物.对于相邻摆放的一些物品,如果过于相似会让人觉得无聊,如果差别过大又会让人觉 得突兀.为了让人们对这次世博会的展出满意,QQ需要知道一些相邻物品的“

BZOJ 3653 谈笑风生

ORZ blutrex...... 主席树. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 1000500 #define maxq 1000500 #define maxe 1600500 using namespace std; struct edge { long long v,nxt; }e[maxe]; struct an

BZOJ 2653: middle [主席树 中位数]

传送门 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 我会使用一些方式强制你在线. 最后一句话太可怕了$QAQ$ 首先需要知道怎么求中位数: 二分答案,$\ge$的为$1$,$<$的为$-1$,如果和$\ge 0$说明当前答案$\le$中位数 最大中位数?$GSS$! 只要求$[a,b].rm+(b,c)

【NOI模拟】谈笑风生(主席树)

题目描述 设 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.

BZOJ 3514 LCT+主席树

思路: //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=400500; int n,m,k,type,ch[N][2],fa[N],minn[N],rev[N],q[N],top,pre[N]; int root[N],tree[N*50],lson[N*50],rson[N*50],cnt,xx,yy,ans; struct Road{int x,y,wei;}road[N]; bool isr

BZOJ 2653 middle | 主席树

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2653 题解: 设答案为ans,把大于等于ans的记为1,小于的记为-1,这样可以知道当前ans是大了还是小了 然后二分答案,就是求最大子段和的问题,根据网上的题解:[b,c]是必选的,然后选[a,b]和[c,d]的最大字段和就行了 #include<cstdio> #include<cstring> #include<algorithm> #define N 20

bzoj 3545&amp;&amp;3551: [ONTAK2010]Peaks &amp;&amp;加强版 平衡树&amp;&amp;并查集合并树&amp;&amp;主席树

3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Status] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. I