洛谷P3603 || bzoj 4763 雪辉 && bzoj4812: [Ynoi2017]由乃打扑克
https://www.luogu.org/problemnew/show/P3603
https://www.lydsy.com/JudgeOnline/problem.php?id=4763
就是先树分块,取所有的块顶为关键点
那么任意点与它祖先中离它最近的关键点的距离为根号级别
先预处理出任意两个关键点之间的路径上有的值的bitset
(vv[i][j][k]表示i到j的路径上是否出现值k)
那么,只需要在询问时,对于路径(a,b),得到它路径上有的值的bitset;对于每个询问,把所有得到的bitset或一下就行了
得到bitset的方法见代码。。。
复杂度:n*(sqrt(n)+30000/32)
以下代码常数超大!为了卡常特意手写了bitset,还把块大小改到550(不是根号,实测这样更快...)
#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<bitset>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int n,m,F;
vector<int> e[];
int dd[];
const int bsz=;
ull lft[];
void init()
{
lft[]=;
for(int i=;i<;i++) lft[i]=lft[i-]<<;
}
struct bs
{
ull d[bsz];
int _Find_first_zero()
{
for(int i=;i<bsz;i++)
if(d[i]!=0xffffffffffffffff)
return (i<<)+__builtin_ffsll(~d[i])-;
}
void reset()
{
for(int i=;i<bsz;i++) d[i]=;
}
void set(int p,bool q=)
{
if(q) d[p>>]|=lft[p-((p>>)<<)];
else d[p>>]&=~lft[p-((p>>)<<)];
}
int count()
{
int ans=;
for(int i=;i<bsz;i++) ans+=__builtin_popcountll(d[i]);
return ans;
}
bs &operator|=(const bs &b)
{
for(int i=;i<bsz;i++) d[i]|=b.d[i];
return *this;
}
};
int bl[],rt[],cnt;
const int sz=;
namespace GBLOCK
{
int st[],tp;
void dfs(int u,int fa)
{
int i,ltp=tp;
for(i=;i<e[u].size();i++)
if(e[u][i]!=fa)
{
dfs(e[u][i],u);
if(tp-ltp>=sz)
{
rt[++cnt]=u;
while(tp!=ltp) bl[st[tp--]]=cnt;
}
}
st[++tp]=u;
}
void work()
{
dfs(,);
++cnt;rt[cnt]=;
while(tp) bl[st[tp--]]=cnt;
}
}
namespace LCA
{
int anc[][],dep[],l2n=;
void dfs(int u,int fa)
{
int i;
anc[u][]=fa;
dep[u]=dep[fa]+;
for(i=;i<=l2n;i++)
anc[u][i]=anc[anc[u][i-]][i-];
for(i=;i<e[u].size();i++)
if(e[u][i]!=fa)
dfs(e[u][i],u);
}
int lca(int x,int y)
{
int t,i;
if(dep[x]<dep[y]){t=x;x=y;y=t;}
for(t=dep[x]-dep[y],i=;t>;t>>=,i++)
if(t&) x=anc[x][i];
if(x==y) return x;
for(i=l2n;i>=;i--)
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
return anc[x][];
}
}
using LCA::lca;
using LCA::dep;
using LCA::anc;
int nn[],nnn;
bs vv[][];//vv[i][j]:rt[i],rt[j]间答案
int num[];bs vis;
namespace PRE
{
int s;
void dfs(int u,int fa)
{
int i;
if(!num[dd[u]]) vis.set(dd[u]);
++num[dd[u]];
if(nn[u]) vv[s][nn[u]]=vis;
for(i=;i<e[u].size();i++)
if(e[u][i]!=fa)
dfs(e[u][i],u);
--num[dd[u]];
if(!num[dd[u]]) vis.set(dd[u],);
}
void work()
{
int i;
for(i=;i<=cnt;i++)
if(!nn[rt[i]])
nn[rt[i]]=++nnn;
for(i=;i<=n;i++)
if(nn[i])
{
s=nn[i];
dfs(i,);
}
}
}
bs tt;
void jump1(int &x,int ed)
{
if(ed==-) ed=rt[bl[x]];
while(x!=ed)
{
tt.set(dd[x]);
x=anc[x][];
}
tt.set(dd[x]);
}
void jump2(int &x,int ed)
{
int x1=x;
while(x1!=&&dep[rt[bl[x1]]]>=dep[ed]) x1=rt[bl[x1]];
tt|=vv[nn[x]][nn[x1]];
x=x1;
}
int main()
{ init();
int i,a,b,a1,a2,t,lans=,l;
scanf("%d%d%d",&n,&m,&F);
for(i=;i<=n;i++) scanf("%d",&dd[i]);
for(i=;i<n;i++)
{
scanf("%d%d",&a,&b);
e[a].pb(b);e[b].pb(a);
}
GBLOCK::work();LCA::dfs(,);PRE::work();
while(m--)
{
scanf("%d",&t);tt.reset();
for(i=;i<=t;i++)
{
scanf("%d%d",&a,&b);
if(F) a^=lans,b^=lans;
l=lca(a,b);
if(a!=&&dep[rt[bl[a]]]>=dep[l]) jump1(a,-);
if(b!=&&dep[rt[bl[b]]]>=dep[l]) jump1(b,-);
jump2(a,l);
jump2(b,l);
jump1(a,l);jump1(b,l);
}
a1=tt.count();
a2=tt._Find_first_zero();
printf("%d %d\n",a1,a2);
lans=a1+a2;
}
return ;
}
此方法相比直接分块然后处理边角,常数还是算小的,能够比bzoj2589https://www.cnblogs.com/hehe54321/p/9463519.html里面的做法快,但是还是过不去...
失败代码:
#pragma GCC optimize(3)
//#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned ul;
typedef pair<int,int> pii;
char B[<<],*SS=B;
#define getchar() (*SS++)
template<typename T>
inline void read(T &x)
{
x=;int f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
x*=f;
}
int n,m;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int dd[];
int r[];
const int bsz=;
ul lft[];
void init()
{
lft[]=;
for(int i=;i<;i++) lft[i]=lft[i-]<<;
}
struct bs
{
ul d[bsz];
void reset(){memset(d,,sizeof(d));}
void set(int p,bool q=)
{
if(q) d[p>>]|=lft[p&];
else d[p>>]&=~lft[p&];
}
int count()
{
int ans=;
for(int i=;i<bsz;i++) ans+=__builtin_popcount(d[i]);
return ans;
}
bs &operator|=(const bs &b)
{
for(int i=;i<bsz;i++) d[i]|=b.d[i];
return *this;
}
};
int bl[],rt[],cnt;
const int sz=;
namespace GBLOCK
{
int st[],tp;
void dfs(int u,int fa)
{
int i,ltp=tp;
for(i=f1[u];i;i=e[i].nxt)
if(e[i].to!=fa)
{
dfs(e[i].to,u);
if(tp-ltp>=sz)
{
rt[++cnt]=u;
while(tp!=ltp) bl[st[tp--]]=cnt;
}
}
st[++tp]=u;
}
void work()
{
dfs(,);
++cnt;rt[cnt]=;
while(tp) bl[st[tp--]]=cnt;
}
}
namespace LCA
{
int anc[][],dep[],l2n=;
void dfs(int u,int fa)
{
int i;
anc[u][]=fa;
dep[u]=dep[fa]+;
for(i=;i<=l2n;i++)
anc[u][i]=anc[anc[u][i-]][i-];
for(i=f1[u];i;i=e[i].nxt)
if(e[i].to!=fa)
dfs(e[i].to,u);
}
int lca(int x,int y)
{
int t,i;
if(dep[x]<dep[y]){t=x;x=y;y=t;}
for(t=dep[x]-dep[y],i=;t>;t>>=,i++)
if(t&) x=anc[x][i];
if(x==y) return x;
for(i=l2n;i>=;i--)
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
return anc[x][];
}
}
using LCA::lca;
using LCA::dep;
using LCA::anc;
int nn[],nnn,nn1[];
bs vvv[];int mem;
int vv[][];//vv[i][j]:rt[i],rt[j]间答案
bs vis;
namespace TTT
{
int anr[][],l2n=;
int dnn1[];
void work()
{
int i,j;
for(i=;i<=nnn;i++) anr[i][]=nn[r[nn1[i]]];
//puts("anr");
//for(i=1;i<=nnn;i++) printf("%d ",anr[i][0]);
//puts("");
//return;
for(j=;j<=l2n;j++)
for(i=;i<=nnn;i++)
anr[i][j]=anr[anr[i][j-]][j-];
for(i=;i<=nnn;i++) dnn1[i]=dep[nn1[i]];
}
}
using TTT::anr;
using TTT::dnn1;
namespace PRE
{
void work()
{
int i,j;
for(i=;i<=cnt;i++)
if(!nn[rt[i]])
nn[rt[i]]=++nnn,nn1[nnn]=rt[i];
for(i=;i<=n;i++)
if(nn[i])
{
vis.reset();
j=i;
vis.set(dd[j]);
while(j!=)
{
j=anc[j][];
vis.set(dd[j]);
if(nn[j]) vvv[vv[nn[i]][nn[j]]=++mem]=vis;
}
}
}
}
bs tt;
void jump1(int &x,int ed)
{
if(ed==-) ed=r[x];
while(x!=ed)
{
tt.set(dd[x]);
x=anc[x][];
}
tt.set(dd[x]);
}
void jump2(int &x,int ed)
{
int i,x1=nn[x];
if(!x1) return;
//while(x1!=1&&dep[r[x1]]>=dep[ed]) x1=r[x1];
for(i=TTT::l2n;i>=;i--)
if(dnn1[anr[x1][i]]>=dep[ed])
x1=anr[x1][i];
x1=nn1[x1];
tt|=vvv[vv[nn[x]][nn[x1]]];
x=x1;
}
int t1[];
map<int,int> ma;
int main()
{
//freopen("/tmp/2589/3.in","r",stdin);
//freopen("/tmp/2589/3.ans","w",stdout);
fread(B,,<<,stdin);
init();
int i,a,b,lans=,l;
read(n);read(m);
for(i=;i<=n;i++) read(dd[i]),t1[++t1[]]=dd[i];
sort(t1+,t1+t1[]+);t1[]=unique(t1+,t1+t1[]+)-t1-;
for(i=;i<=t1[];i++) ma[t1[i]]=i;
for(i=;i<=n;i++) dd[i]=ma[dd[i]];
for(i=;i<n;i++)
{
read(a);read(b);
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
}
GBLOCK::work();LCA::dfs(,);PRE::work();
for(i=;i<=n;i++) r[i]=rt[bl[i]];
TTT::work();
while(m--)
{
tt.reset();
read(a);read(b);
a^=lans;
l=lca(a,b);
if(dep[r[a]]>=dep[l]) jump1(a,-);
if(dep[r[b]]>=dep[l]) jump1(b,-);
jump2(a,l);
jump2(b,l);
jump1(a,l);jump1(b,l);
lans=tt.count();
printf("%d\n",lans);
}
return ;
}
https://www.lydsy.com/JudgeOnline/problem.php?id=4812
此题也是一样的做法,得到一个bitset,之后统计答案
统计答案的话,对于bitset内每一个数字,拆成一些0~0xffff之间的数处理(因为这样就可以预处理了)
统计答案具体方法不写了。。。
注意:如果直接上面那个改改,是过不去的...常数太大
有效卡常:
1.把预处理任意两个关键点之间信息改为只预处理每个关键点到它祖先中所有关键点的信息
2.vector改邻接表
#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<bitset>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned ul;
typedef pair<int,int> pii;
char B[<<],*SSS=B;
#define getchar() (*SSS++)
int n,m;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int dd[];
const int bsz=;
ul lft[];
ul pw[][];
int low[],high[];ul an[][];
template<typename T>
inline void read(T &x)
{
x=;int f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
x*=f;
}
void init()
{
int j,nt,k;
lft[]=;
for(int i=;i<;i++) lft[i]=lft[i-]<<;
for(ul i=;i<=;i++)
{
pw[i][]=;
for(j=;j<=;j++) pw[i][j]=pw[i][j-]*i;
}
for(ul i=,t;i<;i++)
{
nt=;
t=i;
for(j=;j<;j++)
{
if(i&lft[j]) low[i]++,t^=lft[j];
else break;
}
for(j=;j>=;j--)
{
if(i&lft[j]) high[i]++,t^=lft[j];
else break;
}
if(i!=)
{
for(j=;j<;j++)
{
if(t&lft[j]) nt++;
else
{
for(k=;k<=;k++)
{
an[i][k]+=pw[nt][k];
}
nt=;
}
}
for(k=;k<=;k++)
{
an[i][k]+=pw[nt][k];
}
nt=;
}
}
}
struct bs
{
ul d[bsz];
void reset()
{
memset(d,,sizeof(d));
}
void set(int p,bool q=)
{
if(q) d[p>>]|=lft[p&];
else d[p>>]&=~lft[p&];
}
bs &operator|=(const bs &b)
{
for(int i=;i<bsz;i++) d[i]|=b.d[i];
return *this;
}
ul calc(int k)
{
ul ans=,l=;ul t;
#define CAL(t) \
{\
if(t==0xffff) l+=;\
else\
{\
l+=low[t];ans+=pw[l][k];\
ans+=an[t][k];\
l=high[t];\
}\
}
for(int i=;i<bsz;i++)
{
t=d[i]&0xffff;CAL(t);
t=(d[i]>>);CAL(t);
}
return ans+=pw[l][k];
}
};
int bl[],rt[],cnt;
const int sz=;
namespace GBLOCK
{
int st[],tp;
void dfs(int u,int fa)
{
int k,ltp=tp;
for(k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs(e[k].to,u);
if(tp-ltp>=sz)
{
rt[++cnt]=u;
while(tp!=ltp) bl[st[tp--]]=cnt;
}
}
st[++tp]=u;
}
void work()
{
dfs(,);
++cnt;rt[cnt]=;
while(tp) bl[st[tp--]]=cnt;
}
}
namespace LCA
{
int anc[][],dep[],l2n=;
void dfs(int u,int fa)
{
int k;
anc[u][]=fa;
dep[u]=dep[fa]+;
for(k=;k<=l2n;k++)
anc[u][k]=anc[anc[u][k-]][k-];
for(k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
dfs(e[k].to,u);
}
int lca(int x,int y)
{
int t,i;
if(dep[x]<dep[y]){t=x;x=y;y=t;}
for(t=dep[x]-dep[y],i=;t>;t>>=,i++)
if(t&) x=anc[x][i];
if(x==y) return x;
for(i=l2n;i>=;i--)
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
return anc[x][];
}
}
using LCA::lca;
using LCA::dep;
using LCA::anc;
int nn[],nnn;
bs vv[][];//vv[i][j]:rt[i],rt[j]间答案
int num[];bs vis;
namespace PRE
{
void work()
{
int i,j;
for(i=;i<=cnt;i++)
if(!nn[rt[i]])
nn[rt[i]]=++nnn;
for(i=;i<=n;i++)
if(nn[i])
{
vis.reset();
j=i;vis.set(dd[j]);
vv[nn[i]][nn[i]]=vis;
while(j!=)
{
j=anc[j][];
vis.set(dd[j]);
if(nn[j]) vv[nn[i]][nn[j]]=vis;
}
}
}
}
bs tt;
void jump1(int &x,int ed)
{
if(ed==-) ed=rt[bl[x]];
while(x!=ed)
{
tt.set(dd[x]);
x=anc[x][];
}
tt.set(dd[x]);
}
void jump2(int &x,int ed)
{
int x1=x;
while(x1!=&&dep[rt[bl[x1]]]>=dep[ed]) x1=rt[bl[x1]];
tt|=vv[nn[x]][nn[x1]];
x=x1;
}
int main()
{
//freopen("/tmp/4812/1.in","r",stdin);
//freopen("/tmp/4812/1.ans","w",stdout);
fread(B,,<<,stdin);
init();
int i,a,b,t,l;ul a1,b1;ul lans=;
read(n);read(m);
for(i=;i<=n;i++) read(dd[i]);
for(i=;i<n;i++)
{
read(a);read(b);
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
}
GBLOCK::work();LCA::dfs(,);PRE::work();
while(m--)
{
read(t);tt.reset();
for(i=;i<=t;i++)
{
read(a1);read(b1);
a=a1^lans;b=b1^lans;
l=lca(a,b);
if(a!=&&dep[rt[bl[a]]]>=dep[l]) jump1(a,-);
if(b!=&&dep[rt[bl[b]]]>=dep[l]) jump1(b,-);
jump2(a,l);
jump2(b,l);
jump1(a,l);jump1(b,l);
}
read(t);
lans=tt.calc(t);
printf("%u\n",lans);
}
return ;
}
洛谷P3603 || bzoj 4763 雪辉 && bzoj4812: [Ynoi2017]由乃打扑克的更多相关文章
- [bzoj4763]雪辉&[bzoj4812][Ynoi2017]由乃打扑克
来自FallDream的博客,未经允许,请勿转载,谢谢. cut掉部分题面. 给一个n个点的树,点有点权,有m次询问,每次询问多条链的并有多少种不同的点权以及它的mex mex就是一个集合中最小的没有 ...
- [BZOJ 4763]雪辉
[BZOJ 4763] 雪辉 题意 给定一棵 \(n\) 个点的无根树, 点带权. \(q\) 次询问, 每次给定树上的若干路径, 求这些路径上的点共有多少种不同权值以及这些点的权值组成的集合的 \( ...
- 洛谷 P3307: bzoj 3202: [SDOI2013] 项链
题目传送门:洛谷P3307.这题在bzoj上是权限题. 题意简述: 这题分为两个部分: ① 有一些珠子,每个珠子可以看成一个无序三元组.三元组要满足三个数都在$1$到$m$之间,并且三个数互质,两个珠 ...
- 洛谷 4106 / bzoj 3614 [HEOI2014]逻辑翻译——思路+类似FWT
题目:https://www.luogu.org/problemnew/show/P4106 https://www.lydsy.com/JudgeOnline/problem.php?id=3614 ...
- 洛谷 P3332 BZOJ 3110 [ZJOI2013]K大数查询
题目链接 洛谷 bzoj 题解 整体二分 Code #include<bits/stdc++.h> #define LL long long #define RG register usi ...
- 洛谷 P2486 BZOJ 2243 [SDOI2011]染色
题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221” ...
- 洛谷 P2827 BZOJ 4721 UOJ #264 蚯蚓
题目描述 本题中,我们将用符号表示对c向下取整,例如:. 蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓. 蛐蛐国里现在共有n只蚯蚓(n为正整数).每只 ...
- 洛谷 P2155 BZOJ 2186 codevs 2301 [SDOI2008]沙拉公主的困惑
题目描述 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的 ...
- 洛谷 P2046 BZOJ 2007 海拔(NOI2010)
题目描述 YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作 一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个 ...
随机推荐
- 最全的Android源码目录结构详解【转】
本文转载自:http://blog.csdn.net/yangwen123/article/details/8055025 Android 2.1|-- Makefile|-- bionic ...
- Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stoc
今天在使用yum安装文件时,出现了以下问题: root@localhost opt]# yum update Loaded plugins: fastestmirror Could not retri ...
- 记录下linux好用的命令
http://mp.weixin.qq.com/s/LU1iAWfssv1x-QMX6hJqmQ
- .PHP生成静态html文件的方法
1. [代码][PHP]代码 1,下面使用模版的一个方法! <?php $fp = fopen ("templets.html","a"); ...
- nginx开发_ngx_palloc源码解析
功能简介 ngx_pool_t是nginx开发中最经常使用到的内存容器.对动态内存的封装,由框架进行创建与释放,模块开发过程中仅需要进行内存申请,不需要关注何时释放.常见的pool对象有: 1. ng ...
- fhq-treap简介
\(fhq-treap\)是个好东西啊!无旋转\(treap\)果然是好写,而且还是比较好理解的. 这种数据结构是由神犇fhq发明的.\(Think\ functional!\) fhq神犇说,函数式 ...
- codevs 4768跳石头
传送门 4768 跳石头 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 一年一度的“跳石头”比赛又要开始了! 这项比赛将在 ...
- 【Boost】boost库asio详解2——io_service::run函数无任务时退出的问题
io_service::work类可以使io_service::run函数在没有任务的时候仍然不返回,直至work对象被销毁. void test_asio_nowork() { boost::asi ...
- PB调用C# Windows窗体
以下是PB中的代码:String ls_filenameLong ll_wstyle=1long ll_hwnd,ll_nShowCmdstring ls_lpOperation,ls_lpFile, ...
- js数组,在遍历中删除元素(用 for (var i in arr)是无效的 )
/** * 有效的方式 - 改变下标,控制遍历 */ for (var i = 0; i < arr.length; i++) { if (...) { arr.splice(i, 1); // ...