usaco的题,(吐槽一下,现在uscao不能注册账号,如何科学上网233)。
一个常见的思想,线段树处理。第一次出现时标记为1,第二次求和,再取消标记。对着样例画一画即可。
#include<bits/stdc++.h>
#define N 100000
using namespace std;
int n,cnt;
int pos[N+1],x;
int tmp[N+1];
//struct Tree{
// int l;
// int r;
// int data;
//};Tree T[N*4+1];
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,b=1;
char c=nc();
for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
return x*b;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline void modify(int x,int cg)
{
for(;x<=2*n;x+=lowbit(x))
tmp[x]+=cg;
}
inline int sum(int x)
{
int ans=0;
for(;x>0;x-=lowbit(x))
ans+=tmp[x];
return ans;
}
//inline void pushup(int rt)
//{
// T[rt].data=T[rt*2].data+T[rt*2+1].data;
//}
//inline void build(int rt,int l,int r)
//{
// T[rt].l=l,T[rt].r=r;
// if(l==r)return;
// int mid=(l+r)/2;
// build(rt*2,l,mid),build(rt*2+1,mid+1,r);
//}
//inline void modify(int rt,int pos,int val)
//{
// if(T[rt].l==pos&&T[rt].r==pos)
// {
// T[rt].data=val;
// return;
// }
// int mid=(T[rt].l+T[rt].r)/2;
// if(pos<=mid)modify(rt*2,pos,val);
// else modify(rt*2+1,pos,val);
// pushup(rt);
//}
//inline int qurry(int rt,int l,int r)
//{
// if(T[rt].l==l&&T[rt].r==r)
// return T[rt].data;
// int mid=(T[rt].l+T[rt].r)/2;
// if(r<=mid)return qurry(rt*2,l,r);
// else if(l>mid)return qurry(rt*2+1,l,r);
// else return qurry(rt*2,l,mid)+qurry(rt*2+1,mid+1,r);
//}
int main()
{
//freopen("in.txt","r",stdin);
n=read();
//build(1,1,2*n);
for(int i=1;i<=2*n;i++)
{
x=read();
if(pos[x])
{
//cnt+=qurry(1,pos[x]+1,i);
//modify(1,pos[x],0);
cnt+=sum(i)-sum(pos[x]);
modify(pos[x],-1);
}
else
{
pos[x]=i;
//modify(1,pos[x],1);
modify(pos[x],1);
}
}
cout<<cnt;
return 0;
}
话说线段树真心慢,改成树状数组后快了好多好多,还好写233。