【dfs序】【二分】【主席树】【分块】bzoj3351 [ioi2009]Regions

http://dzy493941464.sinaapp.com/archives/96

那个SIZE貌似必须设成R*R/Q?不知为啥,自己算的不是这个的说。

本机AC,线上TLE。

#include<cstdio>
#include<set>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
int f,C;
void R(int &x){
    C=0;f=1;
    for(;C<‘0‘||C>‘9‘;C=getchar())if(C==‘-‘)f=-1;
    for(x=0;C>=‘0‘&&C<=‘9‘;C=getchar())(x*=10)+=(C-‘0‘);
    x*=f;
}
void P(int x){
    if(x<10)putchar(x+‘0‘);
    else{P(x/10);putchar(x%10+‘0‘);}
}
typedef double db;
#define N 200001
vector<int>Over,Nodes[N],col_in_sub[N];
typedef vector<int>::iterator ER;
int v[N],next[N],first[N],en,sz;
void AddEdge(int U,int V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
multiset<int>S;
int anss[701][701];
int n,K,m,a[N],Ls[N],Rs[N],pl[N];
int root[N],e;
struct Node{int v,lc,rc;}T[N*24];
void Insert(int pre,int cur,int p,int l,int r)
{
    if(l==r)
      {
        T[cur].v=T[pre].v+1;
        return;
      }
    int m=(l+r>>1);
    if(p<=m)
      {
        T[cur].lc=++e; T[cur].rc=T[pre].rc;
        Insert(T[pre].lc,T[cur].lc,p,l,m);
      }
    else
      {
        T[cur].rc=++e; T[cur].lc=T[pre].lc;
        Insert(T[pre].rc,T[cur].rc,p,m+1,r);
      }
    T[cur].v=T[T[cur].lc].v+T[T[cur].rc].v;
}
int Query(int cur,int p,int l,int r)
{
	if(l==r) return T[cur].v;
	int m=(l+r>>1);
	if(p<=m) return Query(T[cur].lc,p,l,m);
	else return Query(T[cur].rc,p,m+1,r);
}
int fa[N],id[N];
void dfs(int U)
{
	root[U]=++e;
	Insert(root[fa[U]],root[U],a[U],1,K);
	Ls[U]=++en;
	if(pl[a[U]]>sz)
	  for(ER it=Over.begin();it!=Over.end();++it)
	    anss[id[*it]][id[a[U]]]+=S.count(*it);
	S.insert(a[U]);
	for(int i=first[U];i;i=next[i])
	  dfs(v[i]);
	Rs[U]=en;
	S.erase(S.find(a[U]));
}
int main()
{
	int x,y;
	R(n); R(K); R(m);
	sz=K*K/m;
	R(a[1]); ++pl[a[1]];
	for(int i=2;i<=n;++i)
	  {
	  	R(x); R(a[i]);
	  	fa[i]=x;
	  	++pl[a[i]];
	  	AddEdge(x,i);
	  }
	en=0;
	for(int i=1;i<=n;++i)
	  {
	  	if(pl[i]>sz)
	      {
	        if(!id[i]) id[i]=++en;
	        Over.push_back(i);
	      }
	    if(pl[a[i]]<=sz) Nodes[a[i]].push_back(i);
	  }
	en=0; dfs(1);
	for(int i=1;i<=n;++i) col_in_sub[a[i]].push_back(Ls[i]);
	for(int i=1;i<=n;++i) sort(col_in_sub[i].begin(),col_in_sub[i].end());
	for(;m;--m)
	  {
	  	R(x); R(y);
	  	if(pl[x]>sz&&pl[y]>sz) P(anss[id[x]][id[y]]),puts("");
	  	else if(pl[x]<=sz)
	  	  {
	  	  	int ans=0;
	  	  	for(ER it=Nodes[x].begin();it!=Nodes[x].end();++it) if(Ls[*it]!=Rs[*it])
	  	  	  ans+=(upper_bound(col_in_sub[y].begin(),col_in_sub[y].end(),Rs[*it])-
				  	lower_bound(col_in_sub[y].begin(),col_in_sub[y].end(),Ls[*it]+1));
			P(ans); puts("");
	  	  }
	  	else
	  	  {
	  	  	int ans=0;
	  	  	for(ER it=Nodes[y].begin();it!=Nodes[y].end();++it)
	  	  	  ans+=Query(root[fa[*it]],x,1,K);
			P(ans); puts("");
	  	  }
	  }
	return 0;
}
时间: 2024-08-07 04:32:52

【dfs序】【二分】【主席树】【分块】bzoj3351 [ioi2009]Regions的相关文章

bzoj4771 -- dfs序+倍增+主席树

先考虑没有深度限制的情况. 先将每个节点的权值设为1,对于颜色相同且在dfs序中最近的2个点,用倍增求出lca并将它的权值减一.然后子树中不同的颜色种数就是子树的权值和了. 有深度限制时,考虑以深度为时间建立主席树. 将每个点按深度排序,枚举一遍.对每种颜色开一个set,枚举到一个点时将它在dfs序中的位置加入set中并更新就可以了. 时间复杂度O(T*(nlogn+mlogn)) 代码: #include<iostream> #include<cstdio> #include&l

bzoj 3744: Gty的妹子序列 主席树+分块

3744: Gty的妹子序列 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 101  Solved: 34[Submit][Status] Description 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakse

Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)

思路: dfs序其实是很水的东西.  和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的时候, 我们要查询一下赋值前子树最小值是不是0, 如果是的话, 要让该子树父节点变成0, 否则变0的信息会丢失. 细节参见代码: #include <cstdio> #include <cstring> #include <algorithm> #include <i

bzoj2653 -- 二分+主席树

对于每一个询问二分答案. 设当前答案为x,将>=x的数的权值设为1,<x的数的权值设为-1. 当 [b+1,c-1]的权值和+[a,b]权值和最大的后缀+[c,d]权值和最大的前缀>=0时x可行. 先对每个数离散,然后以每个值建立主席树记录区间和.最大前缀.最大后缀就可以了. 时间复杂度:O(n*log3n) 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #inclu

Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)

题目链接  Tree and Queries 题目大意  给出一棵树和每个节点的颜色.每次询问vj, kj 你需要回答在以vj为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少为kj. (莫队居然可以过) 首先转DFS序,这样就变成了区间查询. 然后直接套用莫队,求出每次询问状态下的t[],t[k]表示当前区间内拥有k个节点的颜色数量. 然后统计t[k] + t[k + 1], ..., t[MAX]即可,这个过程用树状数组维护. #include <bits/stdc++.h>

Luogu P2982 [USACO10FEB]慢下来 Slowing down | dfs序、线段树

题目链接 题目大意: 有一棵N个结点树和N头奶牛,一开始所有奶牛都在一号结点,奶牛们将按从编号1到编号N的顺序依次前往自己的目的地,求每头奶牛在去往自己目的地的途中将会经过多少已经有奶牛的结点. 题解: 可以发现,每一头奶牛到达目的地后,都只会对还未到达目的地的奶牛中,目的地在它目的地子树中的奶牛的答案产生贡献. 比如说在下面这棵树中,一头奶牛到达了图中深色结点,那么在还未到达目的地的奶牛中,只有目的地在深色结点子树中的奶牛才会由深色结点对答案产生贡献. 所以,我们可以在每头奶牛到达目的地后,将

计蒜客16492 building(二分线段树/分块)

题解: 考虑用线段树维护楼的最大值,然后这个问题就很简单了. 每次可以向左二分出比x高的第一个楼a,同理也可以向右二分出另一个楼b,如果a,b都存在,答案就是b-a-1. 注意到二分是可以直接在线段树上进行的,所以复杂度是O(nlogn). 当然这里是用分块做的,更暴力一些. #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace st

2019CCPC网络预选赛 1003 K-th occurrence 后缀自动机 + 二分 + 主席树

题意:给你一个长度为n的字符串,有m次询问,每次询问l到r的子串在原串中第k次出现的位置,如果没有输出-1.n, m均为1e5级别. 思路:后悔没学后缀数组QAQ,其实只要学过后缀数组这个题还是比较好想的.这个问题可以转化为有多少个后缀和后缀l的lcp长度大于等于r - l + 1.我们知道,在后缀数组中,两个后缀i, j的lcp是min(height[rank[j] + 1], height[rank[j] + 2], ....height[rank[i]]).那么,我们可以二分出一个最靠左的

【手动开栈】【dfs序】【树状数组】【Tarjan】bzoj2819 Nim

考虑树状数组区间修改(只对其子树的答案有影响)点查询,每个点记录的是它到根路径上的权值异或和. 答案时query(L)^query(R)^a[lca]. 这种方法在支持区间加法.减法的树上询问的时候可以避免树链剖分. 可能爆栈,考虑手动开栈.(诶诶Tarjan预处理lca的时候怎么没手动开栈?不要在意^_^) 实际上不会爆的. #include<cstdio> #include<stack> #include<algorithm> #include<queue&g