膜拜!dft!
题目来源
不知道是什么地方的集训题,总之很强就对了.
题目描述
题解
题目描述有点问题,y序列少写了个y0.
题意其实是这样的:
每次把[l,r]的序列取出来,进行dft变换,然后再放回原序列.
取出来进行变换是指,重新编号,并且变换只与[l,r]的序列有关,与原序列无关。
那么怎么做呢?先化简式子?理论上应该要化简式子,但是我的数学水平不足以解决这样的式子,那怎么办?先写个 O(n3) 的暴力看看.
于是我们可以发现一些规律:
对1,2,3,4进行两次变换之后变成了1,4,3,2;数值没有变,只有位置变化了;
对1,2,3,4,5,6进行两次变换变成了1,6,5,4,3,2.这下发现规律了!L位置的数不变,[L+1,R]的数反序;
那么询问的答案怎么算?根据打表结果,我们发现,这个变换一次之后的模长平方和等于变换之前的模长平方和。
这些结论我真的不会证明,也没有看到什么有用的题解,如果有大佬会证明的,可以在评论区教育我。
于是写个暴力就有50分了,如果用平衡树维护的话可以拿到100分。
Code
贴一份代码:
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
#define MAXN 105000
int st[MAXN],top;
struct node
{
int ch[MAXN][2],fa[MAXN],rev[MAXN],tot,root,size[MAXN];
LL val[MAXN],sum[MAXN];
void cal(int p)
{
sum[p]=val[p]+sum[ch[p][0]]+sum[ch[p][1]];
size[p]=size[ch[p][0]]+size[ch[p][1]]+1;
return ;
}
void zg(int x,int d)
{
int y=fa[x],z=fa[y];
if(ch[z][0]==y)
{
ch[z][0]=x;
}
else
{
ch[z][1]=x;
}
fa[x]=z;
ch[y][d]=ch[x][!d];
fa[ch[y][d]]=y;
ch[x][!d]=y;
fa[y]=x;
cal(y);
cal(x);
if(!fa[x])
{
root=x;
}
return ;
}
void Rev(int p)
{
swap(ch[p][0],ch[p][1]);
rev[p]^=1;
return ;
}
void push(int p)
{
if(rev[p])
{
if(ch[p][0])
{
Rev(ch[p][0]);
}
if(ch[p][1])
{
Rev(ch[p][1]);
}
rev[p]^=1;
}
return ;
}
void splay(int x,int to=0)
{
if(x==to)
{
return ;
}
int y,z;
st[++top]=x;
for(int i=x;fa[i]!=to;i=fa[i])
{
st[++top]=fa[i];
}
for(;top;--top)
{
push(st[top]);
}
while(fa[x]!=to)
{
y=fa[x];
z=fa[y];
if(z!=to)
{
if(ch[z][0]==y^ch[y][0]==x)
{
zg(x,ch[fa[x]][1]==x);
}
else
{
zg(y,ch[fa[y]][1]==y);
}
}
zg(x,ch[fa[x]][1]==x);
}
return ;
}
void ins(LL v)
{
if(!root)
{
root=1;
++tot;
sum[tot]=val[tot]=v;
size[tot]=1;
return ;
}
int p=root;
while(ch[p][1])
{
p=ch[p][1];
}
size[++tot]=1;
ch[p][1]=tot;
sum[tot]=val[tot]=v;
fa[tot]=p;
splay(p);
return ;
}
int kth(int k)
{
int p=root;
while(p)
{
push(p);
if(k==size[ch[p][0]]+1)
{
break;
}
else if(k<=size[ch[p][0]])
{
p=ch[p][0];
}
else if(k>size[ch[p][0]]+1) //因为没写这两个else,我调了3个小时!简直闯了鬼了!
{
k-=size[ch[p][0]]+1;
p=ch[p][1];
}
}
return p;
}
void print()
{
for(int i=2;i<tot;i++)
{
printf("%d ",val[kth(i)]);
}
putchar('\n');
return ;
}
}T;
int n,q,l,r;
void _r(int& x,bool f=0)
{
char c=getchar();
while(c<'0'||c>'9')
{
f|=(c=='-');
c=getchar();
}
for(x=0;c>='0'&&c<='9';c=getchar())
{
x=(x<<1)+(x<<3)+c-'0';
}
x=f?-x:x;
return ;
}
int o[30],oo;
void _w(LL x)
{
if(x==0ll)
{
putchar('0');
return ;
}
for(oo=0;x;x/=10ll)
{
o[++oo]=x%10ll;
}
for(;oo;--oo)
{
putchar('0'+o[oo]);
}
return ;
}
int main()
{
//freopen("dft.in","r",stdin);
//freopen("dft.out","w",stdout);
_r(n);
T.ins(0);
for(int i=1,x;i<=n;i++)
{
_r(x);
T.ins(1ll*x*x);
}
T.ins(0);
_r(q);
for(int i=1,a,b,c;i<=q;i++)
{
_r(l);
_r(r);
a=T.kth(l+1);
T.splay(a);
b=T.kth(r+2);
T.splay(b,a);
_w(T.sum[T.ch[b][0]]+T.val[a]);
putchar('\n');
T.Rev(T.ch[b][0]);
}
return 0;
}