题解
套路题,直接切掉(果然,我们学校的题温和多了,其他学校的题完全没有思路。。。)
直接手算一下生成函数,再推出递推式就可以矩阵快速幂了
具体方法:之前做过一道更难的题:https://blog.csdn.net/C20180602_csq/article/details/103823671
代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 105
#define MOD 998244353
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
long long n;
int k;
struct node{
long long a[3][3];
friend node operator*(node x,node y)
{
node z;memset(z.a,0,sizeof z.a);
for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++)(z.a[i][j]+=x.a[i][k]*y.a[k][j])%=MOD;
return z;
}
}A,I;
inline long long ksm(long long num,long long k)
{
long long ret=1;
for(;k;k>>=1,num=num*num%MOD)if(k&1)ret=ret*num%MOD;
return ret;
}
inline node ksm(node num,long long k)
{
node ret=I;
for(;k;k>>=1,num=num*num)if(k&1)ret=ret*num;
return ret;
}
inline void solve1()
{
I.a[0][0]=I.a[0][1]=1;
A.a[0][0]=A.a[0][1]=A.a[1][0]=1,A.a[1][1]=2;
if(!n)printf("1\n");
else printf("%lld\n",(ksm(A,n).a[0][0]-ksm(A,n-1).a[0][0]+MOD)%MOD);
}
inline void solve2()
{
I.a[0][0]=I.a[0][2]=1;
A.a[0][0]=A.a[0][1]=A.a[0][2]=1;
A.a[1][0]=A.a[1][2]=MOD-1;
A.a[2][0]=2,A.a[2][2]=3;
if(n<2)printf("1\n");
else printf("%lld\n",((ksm(A,n).a[0][0]-2*ksm(A,n-1).a[0][0]+ksm(A,n-2).a[0][0])%MOD+MOD)%MOD);
}
int main()
{
freopen("generate.in","r",stdin);
freopen("generate.out","w",stdout);
n=getint(),k=getint();
I.a[0][0]=I.a[1][1]=I.a[2][2]=1;
if(k==0)printf("%lld\n",ksm(2,max(n-1,0ll)));
if(k==1)solve1();
if(k==2)solve2();
}
题解
很明显的离线线段树
(考试的时候明明写的正解,却以为自己只写了60,结果后来测出来只有10分,当场惊讶。。。)
(然后调了1h发现自己pushdown的时候把len写成了sum,竟然还有10分!!!)
(改了之后就过了。。。)
所以考试的时候不要脑抽啊啊啊
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 100005
#define LL long long
#define lc i<<1
#define rc i<<1|1
struct node{
int l,r,len;
LL sum,la;
}a[32][N<<2];
struct qnode{
int l,r,k,id;
bool operator < (const qnode t)const{return r<t.r;}
}q[2*N];
LL ans[2*N];
int val[N],pos[N][32],tmp[32];
void pushdown(int flg,int i)
{
if(a[flg][i].la&&a[flg][i].l<a[flg][i].r){
a[flg][lc].sum+=1ll*a[flg][i].la*a[flg][lc].len;
a[flg][rc].sum+=1ll*a[flg][i].la*a[flg][rc].len;
a[flg][lc].la+=a[flg][i].la;
a[flg][rc].la+=a[flg][i].la;
a[flg][i].la=0;
}
}
void build(int flg,int i,int l,int r)
{
a[flg][i].l=l;a[flg][i].r=r;
a[flg][i].len=r-l+1;
if(l==r)return;
int mid=(l+r)>>1;
build(flg,lc,l,mid);
build(flg,rc,mid+1,r);
}
void insert(int flg,int i,int l,int r)
{
if(a[flg][i].l>r||a[flg][i].r<l)return;
pushdown(flg,i);
if(l<=a[flg][i].l&&a[flg][i].r<=r){
a[flg][i].la++;
a[flg][i].sum+=a[flg][i].len;
return;
}
insert(flg,lc,l,r);insert(flg,rc,l,r);
a[flg][i].sum=a[flg][lc].sum+a[flg][rc].sum;
}
LL query(int flg,int i,int l,int r)
{
if(a[flg][i].l>r||a[flg][i].r<l)return 0ll;
pushdown(flg,i);
if(l<=a[flg][i].l&&a[flg][i].r<=r)return a[flg][i].sum;
return query(flg,lc,l,r)+query(flg,rc,l,r);
}
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
int n,m,i,j,k;
n=gi();m=gi();
for(i=1;i<=n;i++)val[i]=gi();
for(i=1;i<=m;i++){q[i].l=gi();q[i].r=gi();q[i].k=gi();q[i].id=i;}
sort(q+1,q+m+1);
for(k=0;k<=30;k++)build(k,1,1,n);
for(i=1,j=1;i<=n;i++){
for(k=0;k<=30;k++){
if((val[i]>>k)&1) pos[i][k]=pos[i-1][k];
else pos[i][k]=i;
}
memcpy(tmp,pos[i],sizeof(pos[i]));
tmp[31]=0;sort(tmp,tmp+32);
for(k=0;k<=30;k++)insert(k,1,tmp[k]+1,tmp[k+1]);
while(j<=m&&q[j].r==i){
ans[q[j].id]+=query(q[j].k,1,q[j].l,q[j].r);
j++;
}
}
for(i=1;i<=m;i++)
printf("%lld\n",ans[i]);
}
题解
先分析一下问题:一个路径怎样才会被完全包含
我们可以把路径(u,v)分为两类:
1、u、v不是祖先关系
那么对包含它的路径(x,y)的要求就是(x在u子树,且y在v子树)或(x在v子树,且y在u子树)
2、u、v是祖先关系
假设u是v的祖先
我们可以用倍增找到u通向v的儿子z
然后路径(x,y)的要求就是(x不在z子树且y在v子树)或(y不在z子树且x在v子树)
发现这种类型的限制条件可以转换到dfs序上来表达
然后就可以用KD树来解决(如果离线的话直接CDQ就可以了)
调了两个小时,发现自己把mx[0][0]和mx[0][1]设成了INF,还一直以为是对的。。。
应该把mi[0][0]和mi[0][1]设成INF
然后就过了
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi(){
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 200005
#define LOG 16
#define lc ch[i][0]
#define rc ch[i][1]
int n,m;
int fir[N],to[2*N],nxt[2*N],cnt;
int f[N][LOG+2],siz[N],dep[N];
int in[N],out[N],dfn;
int treearray[N],val[N];
int D,tmp[N],TCT,rt,tot;
int a[N][2],ch[N][2],mi[N][2],mx[N][2],sz[N],sum[N],vl[N];
int zb[2],qmx[2],ans;
char s[4];
void adde(int a,int b)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
void dfs(int u)
{
in[u]=++dfn;
siz[u]=1;dep[u]=dep[f[u][0]]+1;
for(int v,p=fir[u];p;p=nxt[p]){
v=to[p];
if(v!=f[u][0]){
f[v][0]=u;
dfs(v);
siz[u]+=siz[v];
}
}
out[u]=dfn;
}
inline int getk(int x,int k)
{
for(int i=LOG;i>=0;i--)
if(k&(1<<i)) x=f[x][i];
return x;
}
inline int getd(int x,int d)
{
return getk(x,dep[x]-d);
}
inline int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
x=getd(x,dep[y]);
if(x==y)return x;
for(int i=LOG;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline void update(int x,int k)
{
while(x<=n){
treearray[x]+=k;
x+=(x&-x);
}
}
inline int getsum(int x)
{
int sum=0;
while(x){
sum+=treearray[x];
x-=(x&-x);
}
return sum;
}
//long long quecon;
inline void pushup(int i)
{
mx[i][0]=max(max(mx[lc][0],mx[rc][0]),a[i][0]);
mx[i][1]=max(max(mx[lc][1],mx[rc][1]),a[i][1]);
mi[i][0]=min(min(mi[lc][0],mi[rc][0]),a[i][0]);
mi[i][1]=min(min(mi[lc][1],mi[rc][1]),a[i][1]);
sum[i]=sum[lc]+sum[rc]+vl[i];sz[i]=sz[lc]+sz[rc]+1;
}
inline bool cmp(const int &x,const int &y){return a[x][D]<a[y][D];}
void build(int &i,int l,int r,int d)
{
int mid=(l+r)>>1;D=d;
nth_element(tmp+l,tmp+mid,tmp+r+1,cmp);
i=tmp[mid];lc=rc=0;
if(l<mid)build(lc,l,mid-1,d^1);
if(r>mid)build(rc,mid+1,r,d^1);
pushup(i);
}
void prebuild(int i)
{
if(!i)return;
prebuild(lc);
tmp[++TCT]=i;
prebuild(rc);
}
void insert(int &i,int d,int k)
{
if(!i){
i=++tot;sum[i]=vl[i]=k;
a[i][0]=mx[i][0]=mi[i][0]=zb[0];
a[i][1]=mx[i][1]=mi[i][1]=zb[1];
return;
}
bool flg=(zb[d]>=a[i][d]);
insert(ch[i][flg],d^1,k);
pushup(i);
if(1.0*max(sz[lc],sz[rc])>0.75*sz[i]){
TCT=0;prebuild(i);
build(i,1,TCT,d);
}
}
void query(int i)
{
//quecon++;
if(!i||qmx[0]<mi[i][0]||qmx[1]<mi[i][1])return;
if(mx[i][0]<=qmx[0]&&mx[i][1]<=qmx[1]){ans+=sum[i];return;}
if(a[i][0]<=qmx[0]&&a[i][1]<=qmx[1])ans+=vl[i];
query(lc);query(rc);
}
void addmat(int l1,int r1,int l2,int r2)
{
zb[0]=l1,zb[1]=l2,insert(rt,0,1);
if(r1<n)zb[0]=r1+1,zb[1]=l2,insert(rt,0,-1);
if(r2<n)zb[0]=l1,zb[1]=r2+1,insert(rt,0,-1);
if(r1<n&&r2<n)zb[0]=r1+1,zb[1]=r2+1,insert(rt,0,1);
}
int main()
{
freopen("water.in","r",stdin);
freopen("water.out","w",stdout);
mi[0][0]=mi[0][1]=1000000000;
int i,j,u,v,z;n=gi();m=gi();
for(i=1;i<n;i++){
u=gi();v=gi();
adde(u,v);
}
dfs(1);
for(j=1;j<=LOG;j++)
for(i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
for(i=1;i<=m;i++){
scanf("%s",s);
u=gi()^ans;v=gi()^ans;
if(in[u]>in[v])swap(u,v);
if(s[0]=='A'){
if(u==v){
val[u]++;
update(in[u],1);
update(out[u]+1,-1);
continue;
}
if(in[u]<=in[v]&&out[v]<=out[u]){
z=getd(v,dep[u]+1);
addmat(1,in[z]-1,in[v],out[v]);
if(out[z]<n)addmat(in[v],out[v],out[z]+1,n);
}
else addmat(in[u],out[u],in[v],out[v]);
}
else{
int lca=LCA(u,v);
ans=getsum(in[u])+getsum(in[v])-2*getsum(in[lca])+val[lca];
qmx[0]=in[u];qmx[1]=in[v];query(rt);
printf("%d\n",ans);
}
}
//freopen("CON","w",stdout);
//printf("%lld %d",quecon,tot);
}