P3870 [TJOI2009]开关
题目
算法分析
用分块来解决的话思路很简单,就是把整个序列进行分块,区间 [ a , b ] [a,b] [a,b]按照三个部分(前小块,中部整块,后小块)大段维护,局部朴素的算法来搞就行了。
具体代码如下:(
f
[
i
]
f[i]
f[i]表示灯的状态)
注意本题中灯开
o
r
or
or关的状态改变的时候可用
f
[
i
]
f[i]
f[i] ^
=
1
=1
=1来实现,否则会TLE。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define rg register
using namespace std;
typedef long long ll;
inline int sread()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return f*x;
}
const int maxn=100000;
int n,m,a,b,klen,ans,opt;
int knum[maxn],f[maxn],fchange[maxn];
void change_(int a,int b)
{
if(knum[a]==knum[b])
{
for(rg int i=a;i<=b;++i) f[i]^=1;
return;
}
for(rg int i=a;knum[i]==knum[a];i++) f[i]^=1;
for(rg int i=b;knum[i]==knum[b];i--) f[i]^=1;
for(rg int i=knum[a]+1;i<=knum[b]-1;++i) fchange[i]^=1;
return;
}
void search_(int a,int b)
{
for(rg int i=a;i<=b;++i)
ans+=(f[i]+fchange[knum[i]])%2;
printf("%d\n",ans);
}
int main()
{
n=sread(); m=sread();
klen=sqrt(n);
for(rg int i=1;i<=n;++i) knum[i]=(i-1)/klen+1;
for(rg int i=1;i<=m;++i)
{
opt=sread(); a=sread(); b=sread();
if(opt==0) change_(a,b);
else if(opt==1) search_(a,b);
ans=0;
}
return 0;
}
反思与总结
因为前几次提交都是TLE,很蓝瘦。
最开始是这样搞
f[i] = (f[i] + 1) % 2;
20分TLE emm后来这样搞
f[i] ^= 1;
60分TLE emm接着发现了这个
if( ( f[i] + fchange[ knum[i] ]) % 2 ) ans++;
搞成这样
ans += ( f[i] + fchange[ knum[i] ] ) % 2;
OK Accepted
当测试状态从一片蓝变成一片绿的时候心情十分舒畅。
P2709 小B的询问【普通莫队模板】
莫队相关知识及本题思路分析详见 这篇文章
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define rg register
using namespace std;
typedef long long ll;
inline int sread()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return f*x;
}
const int maxn=50010;
int n,m,k,ql,qr,klen,ans;
int a[maxn];
int sum[maxn];
int ans_[maxn];
struct node{
int l;
int r;
int num;
}q[maxn];
bool cmp1(node a,node b)
{
return ((a.r/klen)==(b.r/klen))?a.l<b.l:a.r<b.r;
}
inline void add(int x)
{
sum[a[x]]++;
ans+=2*sum[a[x]]-1;
}
inline void del(int x)
{
sum[a[x]]--;
ans-=2*sum[a[x]]+1;
}
int main()
{
n=sread(); m=sread(); k=sread();
klen=sqrt(n);
for(rg int i=1;i<=n;++i)
a[i]=sread();
for(rg int i=1;i<=m;++i)
{
q[i].l=sread(); q[i].r=sread();
q[i].num=i;
}
sort(q+1,q+m+1,cmp1);
int l=1,r=0;
for(rg int i=1;i<=m;++i)
{
while(l<q[i].l) { del(l); l++; }
while(l>q[i].l) { l--; add(l); }
while(r>q[i].r) { del(r); r--; }
while(r<q[i].r) { r++; add(r); }
ans_[q[i].num]=ans;
}
for(rg int i=1;i<=m;++i)
{
printf("%d\n",ans_[i]);
}
}