您的位置:首页 > 其它

Codeforces 840D Destiny 【主席树】

2017-08-20 21:58 330 查看
题目地址:点击打开链接

先考虑问题的简化版。假设l和r固定不变,由于数字范围同样是1到n,故我们可以考虑用线段树维护一个计数表(统计1有多少个,2有多少个,3有多少个,。。。),每个点的权值表示值在区间[l,r]之间的数的个数。

那么对于每次查询的k,先计算出((r-l+1)/k)+1(记为P),那么目标就是从线段树中找出权值大于等于P的最左边的叶子节点。

直接从线段树的顶部开始往下搜,如果搜到最底部的话便返回当前叶子节点代表的数值,否则如果左边分支的权值大于等于P则往左边搜下去,如果左边分支的权值小于P或者左边搜下去的返回值为-1,则往右边分支搜(如果右边分支的权值大于等于P的话)。如果两边都搜不到结果或者小于P的话则返回-1,否则优先返回左边搜到的结果。

可以通过极端情况推导的方法(或者强有力的直觉)来得知,在2<=k<=5的范围内,每次查询的时间复杂度差不多是O(logn)。

而对于原问题而言,只需要按照数列的顺序从左到右维护一棵主席树,然后每次要查询的线段树便是第r次更新的线段树减去第l-1次更新的线段树。

代码如下:

#include <bits/stdc++.h>

using namespace std;

#define sfi(a) scanf("%d",&a)
#define sfd(a) scanf("%lf",&a)
#define sfl(a) scanf("%lld",&a)
#define sfs(a) scanf("%s",a)

#define rep(i,a,b) for(int i=int(a);i<int(b);++i)
#define dwn(i,b,a) for(int i=int(b-1);i>=int(a);--i)

#define mem(a,p) memset(a,p,sizeof(a))

typedef long long LL;
typedef unsigned UINT;
typedef unsigned long long ULL;

struct Chairman_Tree
{
struct node
{
int l,r;
int cnt;
void init()
{
l=r=-1;
cnt=0;
}
};

node a[7000005];
int top;

int root[300005];
int rtop;

int n;

void BuildTree(int l,int r,int p)
{
a[p].init();
if(l==r)return;
int mid=(l+r)>>1;
a[p].l=top++;
BuildTree(l,mid,a[p].l);
a[p].r=top++;
BuildTree(mid+1,r,a[p].r);
}

void init(int nn)
{
n=nn;
top=1;
BuildTree(1,n,0);
rtop=1;
root[0]=0;
}

void Add(int e)
{
a[top].init();
a[top].cnt=a[root[rtop-1]].cnt+1;

root[rtop]=top;
top++;rtop++;

int p1=root[rtop-2],p2=root[rtop-1];
int l=1,r=n;
while(r-l)
{
int mid=(l+r)>>1;
if(e<=mid)
{
a[p2].r=a[p1].r;
a[p2].l=top;
top++;
p2=a[p2].l;
p1=a[p1].l;
a[p2].init();
a[p2].cnt=a[p1].cnt+1;

r=mid;
}
else
{
a[p2].l=a[p1].l;
a[p2].r=top;
top++;
p2=a[p2].r;
p1=a[p1].r;
a[p2].init();
a[p2].cnt=a[p1].cnt+1;

l=mid+1;
}
}
}

int DFS(int p1,int p2,int cnt,int l,int r)
{
if(a[p2].cnt-a[p1].cnt<cnt)return -1;
if(l==r)return l;
int mid=(l+r)>>1;
int ans=DFS(a[p1].l,a[p2].l,cnt,l,mid);
if(ans==-1)ans=DFS(a[p1].r,a[p2].r,cnt,mid+1,r);
return ans;
}

int Query(int l,int r,int k)
{
int p1=root[l-1],p2=root[r];
int cnt=((r-l+1)/k)+1;
return DFS(p1,p2,cnt,1,n);
}

void Print()
{
printf("******************************\n");
printf("RootList: ");
rep(i,0,rtop)printf("%d ",root[i]);
printf("\n");
rep(i,0,top)
{
printf("%d: \tl=%d \tr=%d \tcnt=%d\n",i,a[i].l,a[i].r,a[i].cnt);
}
printf("******************************\n");
}
}C;

int main()
{
int n,q;
while(scanf("%d%d",&n,&q)==2)
{
C.init(n);
rep(i,0,n)
{
int p;
sfi(p);
C.Add(p);
}
rep(i,0,q)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",C.Query(l,r,k));
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: