您的位置:首页 > 其它

BZOJ4564 [Haoi2016]地图

2016-04-29 12:51 183 查看
仙人掌转成序列,然后莫队

仙人掌转成序列的方法是先tarjan找环,对于一个环上的点,如果是环根,那么这个环都属于其子仙人掌,如果不是环根,那么除了他自己这个环上都不是其子仙人掌,这样再dfs一次,对于一个点,优先走其出边里是其子仙人掌的部分,同时对于一个环,把不与环根相连的点的siz加到环根的siz里,这样仙人掌就转成了序列,一个子仙人掌对应的区间就是dfn[x]~dfn[x]+siz[x]-1

之后直接上莫队,用数据结构维护的话是n sqrtn logn的,T到爆,用和GTY的二逼妹子序列相同的方法,对权值分块,维护每块和每个点对答案的贡献,修改是单点修改,这样修改其所在块和这个位置,询问的时候变成sqrtn即可

数据好水啊,我在第二次dfs判这条出边和x是不是在一个环的时候没用tarjan的dfn而用了新dfs序都过了-_-

人生中第一次在BZOJ首A-_-

update:NOI拍照现场看到松爷,吓得我赶紧复习一发仙人掌,结果发现之前的代码有点问题……不过这题数据太弱了,写成啥JB样都能过

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 100010
#define MAXM 300010
#define MAXC 1000010
#define ll long long
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
struct vec{
int to;
int fro;
};
struct que{
int cl;
int v;
int l;
int r;
int k;
int num;
friend bool operator <(que x,que y){
return x.k!=y.k?x.k<y.k:x.r<y.r;
}
};
int A[MAXN],a[MAXN];
int c;
que q[MAXN];
vec mp[MAXM];
int tai[MAXN],cnt=1;
int dfn[MAXN],DFN[MAXN],low[MAXN],ndf[MAXN],tim;
int n,m;
int siz[MAXN];
int ANS[2][MAXC];
int CNT[MAXC];
int Asiz;
int ans[MAXN];
inline void be(int x,int y){
mp[++cnt].to=y;
mp[cnt].fro=tai[x];
tai[x]=cnt;
}
inline void bde(int x,int y){
be(x,y);
be(y,x);
}
void dfs(int x,int f){
int i,y;
DFN[x]=low[x]=++tim;
ndf[tim]=x;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(i==(f^1)){
continue ;
}
if(!DFN[y]){
dfs(y,i);
low[x]=min(low[x],low[y]);
}else{
low[x]=min(low[x],DFN[y]);
}
}
}
void dfs2(int x,int f){
int i,y;
siz[x]=1;
dfn[x]=++tim;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(i==(f^1)){
continue ;
}
if(!dfn[y]&&low[y]>=DFN[x]){
dfs2(y,i);
if(low[y]>DFN[x]){
siz[x]+=siz[y];
}
}
}
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(i==(f^1)){
continue ;
}
if(!dfn[y]&&low[y]<DFN[x]){
dfs2(y,i);
}
}
if(low[x]!=DFN[x]){
siz[ndf[low[x]]]+=siz[x];
}
}
int main(){
int i,j,o,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&A[i]);
c=max(c,A[i]);
}
Asiz=sqrt(c);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
bde(x,y);
}
dfs(1,0);
tim=0;
dfs2(1,0);
for(i=1;i<=n;i++){
a[dfn[i]]=A[i];
}
scanf("%d",&m);
int SIZ=sqrt(n);
for(i=1;i<=m;i++){
scanf("%d%d%d",&q[i].cl,&q[i].l,&q[i].v);
q[i].r=dfn[q[i].l]+siz[q[i].l]-1;
q[i].l=dfn[q[i].l];
q[i].k=q[i].l/SIZ;
q[i].num=i;
}
sort(q+1,q+m+1);
int L=1,R=0;
for(i=1;i<=m;i++){
while(L>q[i].l){
L--;
x=(a[L]-1)/Asiz+1;
if(CNT[a[L]]){
ANS[CNT[a[L]]&1][x]--;
}
CNT[a[L]]++;
ANS[CNT[a[L]]&1][x]++;
}
while(R<q[i].r){
R++;
x=(a[R]-1)/Asiz+1;
if(CNT[a[R]]){
ANS[CNT[a[R]]&1][x]--;
}
CNT[a[R]]++;
ANS[CNT[a[R]]&1][x]++;
}
while(L<q[i].l){
x=(a[L]-1)/Asiz+1;
ANS[CNT[a[L]]&1][x]--;
CNT[a[L]]--;
if(CNT[a[L]]){
ANS[CNT[a[L]]&1][x]++;
}
L++;
}
while(R>q[i].r){
x=(a[R]-1)/Asiz+1;
ANS[CNT[a[R]]&1][x]--;
CNT[a[R]]--;
if(CNT[a[R]]){
ANS[CNT[a[R]]&1][x]++;
}
R--;
}
x=(q[i].v-1)/Asiz+1;
for(j=1;j<x;j++){
ans[q[i].num]+=ANS[q[i].cl][j];
}
for(j=(x-1)*Asiz+1;j<=q[i].v;j++){
if(CNT[j]&&((CNT[j]&1)==q[i].cl)){
ans[q[i].num]++;
}
}
}
for(i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
return 0;
}

/*
7 8
1 2
2 3
3 4
4 1
3 5
5 6
6 7
7 3

5 6
2 1 6 7 7
1 2
1 3
2 4
4 5
4 5
1 3
3
0 3 2
0 3 1
0 1 7

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: