Luogu P1972 [SDOI2009]HH的项链
之前做过的一道题
模拟赛出了原题(当然是改头换面了的)
我竟然没有看出来。。。
考完之后 LinJY找出HH的项链 然后我一看题面就想起怎么做了。。。
发一下之前自己在luogu上写的blog
之前的代码:
#include<cstdio>
#include<cstring>
int a[1000010],n,m,sum[1000010],len=0;
struct nod1{int l,r,id;}b[1000010];
struct nod2{int l,r,c,lc,rc;}tr[1000010];
int before[1000010],next[1000010],v[1000010];
//数组索性全部这么大才过了
//。。。之前RE了3次
int dfs(int l,int r)
{
int x=l,y=r,m=b[(x+y)/2].l;
while(x<=y)
{
while(b[x].l<m)x++;
while(b[y].l>m)y--;
if(x<=y)
{
nod1 t=b[x];b[x]=b[y];b[y]=t;
x++;y--;
}
}
if(l<y)dfs(l,y);
if(x<r)dfs(x,r);
}//按左端点排序
int bt(int l,int r)
{//普通建树
len++;
int now=len;tr[now].l=l;tr[now].r=r;
tr[now].lc=tr[now].rc=-1;tr[now].c=0;
if(l<r)
{
int mid=(l+r)/2;
tr[now].lc=len+1;bt(l,mid);
tr[now].rc=len+1;bt(mid+1,r);
}
//if(l==r)tr[now].c=a[l];
}
int change(int now,int x,int k)//k其实没啥用
{//修改
if(tr[now].l==tr[now].r)
{
tr[now].c=1;
//表示标记这个数是当前区间独一无二的颜色
return 0;
}
int mid=(tr[now].l+tr[now].r)/2;
int lc=tr[now].lc,rc=tr[now].rc;
if(x<=mid)change(lc,x,k);
else if(mid+1<=x) change(rc,x,k);
tr[now].c=tr[lc].c+tr[rc].c;
}
int findsum(int now,int l,int r)
{//普通求和(计数)
if(l==tr[now].l&&r==tr[now].r)
{
return tr[now].c;
}
int mid=(tr[now].l+tr[now].r)/2;
int lc=tr[now].lc,rc=tr[now].rc;
if(r<=mid)return findsum(lc,l,r);
else if(mid+1<=l)return findsum(rc,l,r);
else return findsum(lc,l,mid)+findsum(rc,mid+1,r);
tr[now].c=tr[lc].c+tr[rc].c;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
bt(1,n);//先建一棵空树
for(int i=1;i<=n;i++)
{
if(v[a[i]]==0)
{
change(1,i,1);
v[a[i]]=i;//是这个区间第一个这种颜色
}
else
{//不是的活,标记为现在这个区间上一个颜色的继承人
before[i]=v[a[i]];
v[a[i]]=i;
next[before[i]]=i;
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&b[i].l,&b[i].r);
b[i].id=i;//b数组的id是记录是第几个询问
//因为一会要排序,而答案要按序输出
}//先把全部询问输进来,离线做
dfs(1,m);
for(int i=1;i<=m;i++)
{
for(int j=b[i-1].l;j<b[i].l;j++)
{
change(1,next[j],1);
//让上个区间的颜色把“资格”给他们继承人
}
sum[b[i].id]=findsum(1,b[i].l,b[i].r);
//把找到的这个区间的和记录在答案数组里
}
for(int i=1;i<=m;i++)
printf("%d\n",sum[i]);
}
重新做了一次(好像并没有多大区别qwq只是想贴上来)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int len=0,n,m,pre[4000100],ans[4000100];
struct nod2{int x,next,v;}a[4000100];
struct nod1{int l,r,id;}q[4000100];
struct nod3{int l,r,lc,rc,c;}tr[4000100];
int dfs1(int l,int r)
{
int x=l,y=r,m=q[(x+y)/2].l;
while(x<=y)
{
while(q[x].l<m)x++;
while(q[y].l>m)y--;
if(x<=y)
{
nod1 t=q[x];q[x]=q[y];q[y]=t;
x++;y--;
}
}
if(l<y)dfs1(l,y);
if(x<r)dfs1(x,r);
}
int dfs2(int l,int r)
{
int x=l,y=r,m=q[(x+y)/2].r;
while(x<=y)
{
while(q[x].r<m)x++;
while(q[y].r>m)y--;
if(x<=y)
{
nod1 t=q[x];q[x]=q[y];q[y]=t;
x++;y--;
}
}
if(l<y)dfs2(l,y);
if(x<r)dfs2(x,r);
}
void bt(int l,int r)
{
len++;
int now=len;
tr[now].l=l;tr[now].r=r;
tr[now].lc=tr[now].rc=-1;tr[now].c=0;
if(l<r)
{
int mid=(l+r)/2;
tr[now].lc=len+1;bt(l,mid);
tr[now].rc=len+1;bt(mid+1,r);
}
}
int findsum(int now,int l,int r)
{
//printf("4444 ");
if(tr[now].l==l&&tr[now].r==r)
{
//printf("1111 ");
return tr[now].c;
}
int mid=(tr[now].l+tr[now].r)/2;
int lc=tr[now].lc,rc=tr[now].rc;
if(r<=mid)return findsum(lc,l,r);
else if(mid+1<=l)return findsum(rc,l,r);
else return findsum(lc,l,mid)+findsum(rc,mid+1,r);
}
void change(int now,int x,int k)
{
if(tr[now].l==tr[now].r)
{//printf("11111\n");
tr[now].c=k;return ;
}
int mid=(tr[now].l+tr[now].r)/2;
int lc=tr[now].lc,rc=tr[now].rc;
if(x<=mid)change(lc,x,k);
else if(mid+1<=x)change(rc,x,k);
tr[now].c=tr[lc].c+tr[rc].c;
}
int main()
{
scanf("%d",&n);
bt(1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
int x=a[i].x;
if(pre[x]==0)
{
a[i].v=1;
change(1,i,1);
}
a[pre[x]].next=i;
pre[x]=i;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&q[i].l,&q[i].r);
q[i].id=i;
}
dfs1(1,m);//ok
/*for(int i=1;i<=m;i++)
{
if(q[i].l==q[i+1].l)
{
int t=i+1;
while(q[t].l==q[t+1].l)t++;
dfs2(i,t);
i=t;
}
}*/
/*for(int i=1;i<=m;i++)
{
printf("%d %d |",q[i].l,q[i].r);
}printf("\n");//ok*/
for(int i=1;i<=m;i++)
{
//printf("2222 ");
int l;
l=ans[q[i].id]=findsum(1,q[i].l,q[i].r);
//printf("3333 ");
//printf("%d\n",l);
int nl=q[i+1].l;
if(q[i].l!=nl)
{
for(int j=q[i].l;j<nl;j++)
{
if(a[j].v)
{
//printf("x:%d\n",j);
a[j].v=0;
change(1,j,0);
int y=a[j].next;
a[y].v=1;
if(y<=n&&y>=1)
{
//printf("y:%d\n",y);
change(1,y,1);
}
}
}
}
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
}
#####思路,就是