Description
GX国未来研究的第一人–Hfu教授,最近获得了一份被认为是未来LY国的住民写下的日记。Hfu教授为了通过这份日
记来研究未来LY国的生活,开始着手调查日记中记载的事件。日记中记录了连续N天发生的时间,大约每天发生一
件。事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。Hfu教
授决定用如下的方法分析这些日记:
- 选择日记中连续的一些天作为分析的时间段
- 事件种类t的重要度为t*(这段时间内为t的事件数)
- 计算出所有事件种类的重要度,输出其中的最大值 现在你被要求制作一个帮助Hfu教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。
Input
第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1…XN,Xi表示第i天发生的事件的种类
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。
询问保证不会存在Ai<Aj<Bi<=Bj的情况,且对于任意的i,j不会有Bi=Aj,Ai=Aj。 1<=N<=5510^4
1<=Q<=410^5 1<=Xi<=10^9 (1<=i<=N)
Output
输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度
Sample Input
5 4
9 8 7 8 5
1 2
3 5
4 4
5 5
Sample Output
9
8
8
5
题解
dsu on tree的裸题…
我是在这里学的!
大概思想
每次子树操作的时候 暴力扫子树是 的
我们每次最后扫重儿子那棵树 并且不把重儿子的答案清空 直接将他作为当前这棵子树的答案,再暴力扫其它轻儿子加上贡献
那么再说这题
其实就是历史研究的加强版and卡常版
注意到题目中有一个限制
保证没有A[i]<A[j]<B[i]<=B[j]
也就是说任意两个询问,只可能有包含或者相离两种情况
显然这些询问形成了一棵树
对询问建树
跑dsu
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
inline LL _max(LL x,LL y){return x>y?x:y;}
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(LL x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void print(LL x){write(x);puts("");}
struct LSnode{int y,p;}w[550005];
bool cmp(LSnode n1,LSnode n2){return n1.y<n2.y;}
int cal[550005],LS[550005],fac[550005],n,m,ln;
struct ask{int l,r,pa;}A[2100005];
bool Acmp(ask n1,ask n2){return (n1.l!=n2.l)?(n1.l<n2.l):(n1.r>n2.r);}
struct edge{int x,y,next;}a[2110000];int len,last[550005];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
LL aa[550005];
int sta[550005],tp;
LL tot[550005];
int son[550005];
void pre_tree_node(int x)
{
tot[x]=A[x].r-A[x].l+1;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
pre_tree_node(y);
tot[x]+=tot[y];
if(tot[y]>tot[son[x]])son[x]=y;
}
}
LL ans[550005],ggcc;
int sum[550005],gg[550005],tim;
void add(int u)
{
if(gg[u]!=tim)gg[u]=tim,sum[u]=0;
sum[u]++;ggcc=_max(ggcc,(LL)sum[u]*fac[u]);
}
void updata(int x)
{
int y=son[x];
if(!y)for(int i=A[x].l;i<=A[x].r;i++)add(cal[i]);
else
{
for(int i=A[x].l;i<A[y].l;i++)add(cal[i]);
for(int i=A[y].r+1;i<=A[x].r;i++)add(cal[i]);
}
}
void dsu(int x)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y==son[x])continue;//是重儿子 最后处理
dsu(y);//否则直接计算答案
tim++;
}
if(son[x])dsu(son[x]);
ggcc=ans[son[x]];
updata(x);ans[x]=ggcc;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)w[i].y=read(),w[i].p=i;
sort(w+1,w+1+n,cmp);
int tt=0;
for(int i=1;i<=n;i++)
{
if(w[i].y!=w[i-1].y)tt++;
cal[w[i].p]=tt;fac[tt]=w[i].y;
}
for(int i=1;i<=m;i++)A[i].l=read(),A[i].r=read(),A[i].pa=i;
A[++m].l=0;A[m].r=n+1;A[m].pa=m+1;
sort(A+1,A+1+m,Acmp);
sta[tp=1]=1;
for(int i=2;i<=m;i++)
{
int x;
while(tp)
{
x=sta[tp];
if(A[x].r<A[i].l)tp--;
else break;
}
ins(x,i);sta[++tp]=i;
}
pre_tree_node(1);
dsu(1);
for(int i=1;i<=m;i++)aa[A[i].pa]=ans[i];
for(int i=1;i<m;i++)print(aa[i]);
return 0;
}