10.11 (CSP模拟52联测14)
T1 长春花
第一反应打表,打了半天啥也没发现.最后手摸发现 \((a^{2}+b^{2})\mod {p}\)有循环节.(打表方向完全错了…………)浪费了蛮多时间的.
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e5+5;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n;
namespace bl2{
int res[N],vis[N];
int cnt=0;
void work(){
for(int i=0;i<=n;i++) res[i]=1e9;
for(int i=0;i*i<=n-1;i++) res[i*i]=0,cnt++;
for(int a=0;;a++){
for(int i=0;i<=n-1;i++) vis[i]=0;
for(int b=0;;b++){
ll c=1ll*a*a+1ll*b*b;
if(vis[c%n]) break;
vis[c%n]=1;
if(res[c%n]==1e9) cnt++;
res[c%n]=min(res[c%n],a);
}
if(cnt==n) break;
}
int ans=0;
for(int i=0;i<=n-1;i++) ans=max(ans,res[i]);
printf("%d",ans);
}
}
int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
n=read();
bl2::work();
return 0;
}
T2 紫罗兰
看到题脑子里啥也没有,确实不会应付这种题.
bfs找到最小环,并在bfs时统计答案.
我们从每个点出发bfs.\(dis_{i}\) 是出发点到\(i\)的最短距离.当\(u\)第二次到\(v\)时会产生\(dis_{u}+dis_{v}+1\) 的环但会有冗余部分但只要一直对环取\(min\) 就会消除冗余部分剩下真正的最小环.
对于答案,应为会从环的任意一个点都计算一遍,所以要除以环长,对于奇环,会从两个点各遍历一遍还要除2.
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const int N=10005;
const int M=10005;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
struct Node{
int to,next;
}e[M<<1];
int lk[N],ntot;
void add(int x,int y){
e[++ntot]={y,lk[x]};
lk[x]=ntot;
}
int n,m;
int vis[N];
queue <int> q;
int dis[N],cnt[N];
int huan=1e9;
ll ans=0;
void check(int x,int y){
if((dis[x]==dis[y]&&dis[x]!=2139062143)
||(dis[x]+1==dis[y]&&dis[x]!=2139062143&&dis[y]!=2139062143)){
int len=dis[x]+dis[y]+1;
if(len<huan) { huan=len; ans=1ll*cnt[x]*cnt[y]; }
else if(len==huan) { ans+=1ll*cnt[x]*cnt[y]; }
if(dis[y]==dis[x]+1) { cnt[y]+=cnt[x]; }
return ;
}
if(dis[y]>dis[x]+1){
dis[y]=dis[x]+1;
cnt[y]=cnt[x];
q.push(y);
return ;
}
return;
}
void bfs(int x){
while(!q.empty()) q.pop();
memset(dis,0x7f,sizeof(dis));
memset(cnt,0,sizeof(cnt));
q.push(x);cnt[x]=1;dis[x]=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=lk[x];i;i=e[i].next){
int y=e[i].to;
check(x,y);
}
}
}
int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
add(x,y),add(y,x);
vis[x]=vis[y]=1;
}
for(int i=1;i<=n;i++){
if(!vis[i]) continue;
bfs(i);
}
cerr<<huan<<endl;
ans/=huan;
printf("%lld",(huan&1)?(ans/2):ans);
return 0;
}
T3 天竺葵
考试时跟个傻逼似的,暴力还差点打挂.
一个有限制的最长上升子序列.\(dp_{j}\) 是长度为\(j\) 的最后一位的最小值,发现\(dp\)数组是单增的,所以直接二分转移点.(跟二分优化普通LCS差不多)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N=1e6+5;
inline ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,flag=1;
ll a[N],b[N];
namespace bl1{
ll c[N];
void work(){
int ans=1;
c[ans]=a[1];
for(int i=2;i<=n;i++){
if(a[i]>c[ans]){
c[++ans]=a[i];
}else{
int pos=lower_bound(c+1,c+1+ans,a[i])-c;
c[pos]=a[i];
}
}
printf("%d",ans);
}
}
namespace bl2{
ll f[N],c[N];
int ans;
void work(){
int now=0;
memset(c,0x7f,sizeof(c));
for(int i=1;i<=n;i++){
int pos=lower_bound(c+1,c+1+ans,a[i])-c;
f[i]=pos;ans=max(ans,pos);
c[pos]=min(c[pos],1ll*a[i]*b[pos]);
}
printf("%d",ans);
}
}
int main(){
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++){
b[i]=read();
if(b[i]!=1) flag=0;
}
if(flag==1) bl1::work();
else bl2::work();
return 0;
}
T4 风信子
没记起来超级钢琴(不知道为什么老是记不住典题………………)
和超级钢琴一样不断拆分区间,扔进堆里查询前\(k\)大.
对于\(k==1\)的情况,维护最大值最小值,答案为\(max(ans_{lc},ans_{rc},mx_{lc}-mn_{rc})\)
(pushup一个地方写挂,调了2h………………)
Code
#include<cstdio>
#include<queue>
#define lc (k<<1)
#define rc (k<<1|1)
#define ll long long
using namespace std;
const int N=1e5+5;
const ll inf=1e15;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
ll max(ll x,ll y){
return x>y?x:y;
}
ll min(ll x,ll y){
return x<y?x:y;
}
int n,m,flag=1;
int a[N];
struct Node{
int opt,l,r,k;
}q[N];
namespace bl2{
struct Tree{
ll mx,mn,ans;
int mxpos,mnpos;
int np,xp;
}t[N<<2];
ll lazy[N<<2];
inline Tree push_up(Tree c,Tree d){
Tree e;
e.mn=min(c.mn,d.mn);
e.mx=max(c.mx,d.mx);
e.ans=max(max(c.ans,d.ans),c.mx-d.mn);
e.np=(e.mn==c.mn)?(c.np):(d.np);
e.xp=(e.mx==c.mx)?(c.xp):(d.xp);
if(e.ans==c.ans) e.mnpos=c.mnpos,e.mxpos=c.mxpos;
else if(e.ans==d.ans) e.mnpos=d.mnpos,e.mxpos=d.mxpos;
else if(e.ans==(c.mx-d.mn)) e.mxpos=c.xp,e.mnpos=d.np;
return e;
}
inline void push_down(int k){
if(lazy[k]==inf) return ;
t[lc].mx+=lazy[k],t[rc].mx+=lazy[k];
t[lc].mn+=lazy[k],t[rc].mn+=lazy[k];
lazy[lc]=(lazy[lc]==inf)?(lazy[k]):(lazy[lc]+lazy[k]);
lazy[rc]=(lazy[rc]==inf)?(lazy[k]):(lazy[rc]+lazy[k]);
lazy[k]=inf;
}
void build(int k,int l,int r){
lazy[k]=inf;
if(l==r) { t[k]={a[l],a[l],0,l,l,l,l}; return ; }
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
t[k]=push_up(t[lc],t[rc]);
}
void update(int k,int l,int r,int L,int R,int val){
if(L<=l&&r<=R){
t[k].mx+=val,t[k].mn+=val;
lazy[k]=(lazy[k]==inf)?(val):(lazy[k]+val);
return;
}
int mid=(l+r)>>1;
push_down(k);
if(L<=mid) update(lc,l,mid,L,R,val);
if(R>mid) update(rc,mid+1,r,L,R,val);
t[k]=push_up(t[lc],t[rc]);
}
int query(int k,int l,int r,int pos){
if(l==r) return t[k].mx;
int mid=(l+r)>>1;
push_down(k);
if(pos<=mid) return query(lc,l,mid,pos);
else return query(rc,mid+1,r,pos);
}
Tree query(int k,int l,int r,int L,int R){
if(L<=l&&r<=R) return t[k];
int mid=(l+r)>>1;
push_down(k);
Tree c={-inf,inf,-inf,0,0,0,0},d={-inf,inf,-inf,0,0,0,0};
if(L<=mid) c=query(lc,l,mid,L,R);
if(R>mid) d=query(rc,mid+1,r,L,R);
return push_up(c,d);
}
struct Node{
int lx,ly,rx,ry,x,y;
ll val;
bool operator < (const Node &x) const{
return val<x.val;
}
};
priority_queue <Node> q;
inline int check(Node x){
return (x.lx==x.rx&&x.ly==x.ry);
}
inline void work(int l0,int r0,int l1,int r1){
if(!check({l0,r0,l1,r1})){
// cout<<l0<<" "<<r0<<" "<<l1<<" "<<r1<<endl;
Tree ansl=query(1,1,n,l0,r0);
Tree ansr=query(1,1,n,l1,r1);
q.push({l0,r0,l1,r1,ansl.xp,ansr.np,ansl.mx-ansr.mn});
}else{
Tree ans=query(1,1,n,l0,r0);
q.push({l0,r0,l1,r1,ans.mxpos,ans.mnpos,ans.ans});
}
}
inline void solve1(Node now){
int l=now.lx,r=now.ly,x=now.x,y=now.y;
// cout<<l<<" "<<r<<" "<<x<<" "<<y<<endl;
if(x>l) { work(l,x-1,l,x-1);work(l,x-1,x,r); }
if(x!=y) { work(x,x,x,x); }
if(x<y-1) { work(x,x,x+1,y-1); }
if(y<r) { work(x,x,y+1,r); }
if(x<r) { work(x+1,r,x+1,r); }
}
inline void solve2(Node now){
int l0=now.lx,r0=now.ly,l1=now.rx,r1=now.ry,x=now.x,y=now.y;
if(x>l0) { work(l0,x-1,l1,r1); }
if(l1<y) { work(x,x,l1,y-1); }
if(y<r1) { work(x,x,y+1,r1); }
if(x<r0) { work(x+1,r0,l1,r1); }
}
void work(){
build(1,1,n);
// cout<<query(1,1,n,4,7).mxpos<<" "<<query(1,1,n,4,7).mnpos<<endl;
for(int i=1;i<=m;i++){
int opt=read(),l=read(),r=read(),k=read();
if(opt==1) { update(1,1,n,l,r,k); continue; }
while(!q.empty()) q.pop();
work(l,r,l,r);
ll ans=0;
while(!q.empty()&&k){
Node now=q.top();
q.pop();
int posx=now.x,posy=now.y;
ans+=now.val;
(check(now))?(solve1(now)):(solve2(now));
// cout<<"x:"<<posx<<" "<<"y:"<<posy<<" "<<now.val<<endl;
k--;
}
printf("%lld\n",ans);
}
}
}
int main(){
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
bl2::work();
return 0;
}
10.9 (accoder 2023NOIP A层联测8)
T2 出租
转化成二分图匹配,直接连边不行,考虑Hall定理.
若任意 $ [l,r] $ 的人数大于 $ (r-l+1+d) * k $ 时无解,即 $ \sum_{l}^{r} (val_{i}-k) > k*d $ 时无解求最大子段和比较.
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#define lc (k<<1)
#define rc (k<<1|1)
#define ll long long
using namespace std;
const int N=5e5+5;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,v,d;
int mx[N];
ll val[N];
struct Node{
ll sum,lmax,rmax,dat;
}t[N<<2];
int lazy[N<<2];
void push_up(int k){
t[k].sum=(t[lc].sum+t[rc].sum);
t[k].lmax=max(t[lc].lmax,t[lc].sum+t[rc].lmax);
t[k].rmax=max(t[lc].rmax+t[rc].sum,t[rc].rmax);
t[k].dat=max({t[lc].dat,t[rc].dat,t[lc].rmax+t[rc].lmax});
}
void update(int k,int l,int r,int pos,int val){
if(l==r){
t[k].lmax+=val;t[k].rmax+=val;
t[k].sum+=val,t[k].dat+=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) update(lc,l,mid,pos,val);
else update(rc,mid+1,r,pos,val);
push_up(k);
}
int main(){
freopen("lantern.in","r",stdin);
freopen("lantern.out","w",stdout);
n=read(),m=read(),v=read(),d=read();
for(int i=1;i<=n;i++) update(1,1,n,i,-v);
while(m--){
int x=read(),y=read();
update(1,1,n,x,y);
cout<<t[1].dat<<endl;
(t[1].dat>1ll*v*d)?(printf("NO\n")):(printf("YES\n"));
}
return 0;
}
T3 连通块
设 $ dp_{i,j} $ 表示以\(i\) 为根最大\(dfn\)为\(j\)的最大值,因为只有冲突的点会影响转移所以可以对其重编号,不影响转移的点可以编成一个号,每次用最大值转移.
Code
#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
using namespace std;
const int N=1e5+5;
const ll inf=-1e18;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m;
int a[N];
int dfn[N],dfntime;
pair <int,int> no[N];
vector<int> e[N];
int No[N];
int vis[55][55];
ll dp[N][55],ans=inf;
void dfs(int x,int fa){
for(int i=1;i<=dfntime;i++) dp[x][i]=inf;
dp[x][dfn[x]]=a[x];
for(int y:e[x]){
if(y==fa) continue;
dfs(y,x);
ll mx=inf;
for(int i=1;i<=dfntime;i++) if(!vis[i][dfn[y]]) mx=max(mx,dp[x][i]);
for(int i=1;i<=dfntime;i++) dp[x][i]=max(dp[x][i],dp[y][i]+mx);
}
for(int i=1;i<=dfntime;i++) ans=max(ans,dp[x][i]);
// cout<<ans<<endl;
}
int main(){
freopen("connection.in","r",stdin);
freopen("connection.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++){
int tot=read();
for(int j=1;j<=tot;j++){
int x=read();
e[i].push_back(x),e[x].push_back(i);
}
}
for(int i=1;i<=m;i++){
no[i].first=read(),no[i].second=read();
No[no[i].first]=1,No[no[i].second]=1;
}
++dfntime;
for(int i=1;i<=n;i++) { if(!No[i]) dfn[i]=dfntime; }
for(int i=1;i<=n;i++) { if(No[i]) dfn[i]=++dfntime; }
for(int i=1;i<=m;i++){
vis[dfn[no[i].first]][dfn[no[i].second]]=1;
vis[dfn[no[i].second]][dfn[no[i].first]]=1;
}
dfs(1,0);
printf("%lld",ans);
return 0;
}
T4 跳棋
考虑没有\(?\) 的情况 CF1545B
把两个\(1\)看做一个整体可以向周围空格移动;单独的\(1\)可以在两个\(1\)移动到它是与其中一个\(1\)配对.设有$ a \(个成对的\) 1 \(,\) b $ 个单独的$ 1 $ ,$ ans={{n-a-b}\choose{a}} $
当有$ ? $ 时 考虑$ dp_{i,j,k,0/1/2} $ 表示考虑到$ i \(,有\) j \(个成对,\) k $个单独,这一位选0/成单/成对.
最后乘上系数就行.
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=505;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
ll ksm(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int n;
char ch[N];
int dp[2][N][N][3];
ll fac[N],inv[N];
ll C(int n,int m){
if(n==m) return 1;
if(n<m) return 0;
return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
freopen("checkers.in","r",stdin);
freopen("checkers.out","w",stdout);
scanf("%d",&n);
scanf("%s",ch+1);
fac[0]=1,inv[0]=1;
for(int i=1;i<=n;i++){
fac[i]=1ll*fac[i-1]*i%mod;
inv[i]=ksm(fac[i],mod-2);
}
int now=0;
dp[now][0][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
dp[now^1][j][k][0]=dp[now^1][j][k][1]=dp[now^1][j][k][2]=0;
for(int j=0;j<=n;j++){
for(int k=0;k<=n;k++){
if(ch[i]=='0'||ch[i]=='?')
dp[now^1][j][k][0]=((dp[now][j][k][0]+dp[now][j][k][1])%mod+dp[now][j][k][2])%mod;
if(ch[i]=='1'||ch[i]=='?'){
if(k>=1) dp[now^1][j][k][1]=(dp[now][j][k-1][0]+dp[now][j][k-1][2])%mod;
if(j>=1) dp[now^1][j][k][2]=(dp[now][j-1][k+1][1]);
}
}
}
now^=1;
}
ll ans=0;
for(int i=0;i<=n/2;i++){
for(int j=0;j<=min(n-2*i,(n+1)/2);j++){
int x=(n-i-j);
ll res=((dp[now][i][j][0]+dp[now][i][j][1])%mod+dp[now][i][j][2])%mod;
ans=(ans+C(x,i)*res%mod)%mod;
}
}
printf("%lld",ans);
return 0;
}
10.7 (CSP模拟50)
分治+根号分治
x $ \ge $ lim 修改不超过 \(\sqrt n\) 次 维护差分单点修改,区间查询,因为空间原因,不能全部存下来,所以每根号次重构.(……好像没被卡空间)
x \(<\) lim 对dfs序 分块 散块暴力,整块维护 \(sum[i][j][k]\) 表示 \(i\) 块 mod \(j\) 为 \(k\) 所需要加的值
Code
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<cstring>
using namespace std;
const int N=3e5+5;
const int Std1=550;
const int Std2=250;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
struct Node{
int to,next;
}e[N<<1];
int lk[N],ntot;
void add(int x,int y){
e[++ntot]={y,lk[x]};
lk[x]=ntot;
}
int n,Q;
int dfn[N],dfnx[N],siz[N],dep[N],dfntime;
int mxdep;
void dfs(int x,int fa){
dep[x]=dep[fa]+1;siz[x]=1;
dfn[x]=++dfntime;dfnx[dfntime]=x;
mxdep=max(dep[x],mxdep);
for(int i=lk[x];i;i=e[i].next){
int y=e[i].to;
if(y==fa)
continue;
dfs(y,x);
siz[x]+=siz[y];
}
}
int L[N],R[N];
int len,tot;
void init(){
len=min(Std1,(int)sqrt(n));
tot=(n-1)/len+1;
for(int i=1;i<=tot;i++)
L[i]=R[i-1]+1,R[i]=i*len;
// for(int i=1;i<=tot;i++)
// cout<<L[i]<<" "<<R[i]<<endl;
// cout<<endl;
dfs(1,0);
// for(int i=1;i<=n;i++)
// cout<<"siz:"<<siz[i]<<endl;
// cout<<endl;
}
int val[N];
int sum[Std1+5][Std2+5][Std2+5];
void work1(int v,int x,int y,int z){
int l=dfn[v],r=dfn[v]+siz[v]-1;
int lbe=(l-1)/len+1,rbe=(r-1)/len+1;
// cout<<l<<" "<<r<<endl;
// cout<<lbe<<" "<<rbe<<endl;
if(lbe==rbe){
for(int i=l;i<=r;i++){
if((dep[dfnx[i]]-dep[v])%x==y)
val[dfnx[i]]+=z;
}
return ;
}
for(int i=l;i<=R[lbe];i++){
if((dep[dfnx[i]]-dep[v])%x==y)
val[dfnx[i]]+=z;
}
for(int i=L[rbe];i<=r;i++){
if((dep[dfnx[i]]-dep[v])%x==y)
val[dfnx[i]]+=z;
}
for(int i=lbe+1;i<=rbe-1;i++){
sum[i][x][(dep[v]+y)%x]+=z;
}
}
struct Ques{
int v,x,y,z,l,r;
}q[Std1+5];
int cnt;
vector <Ques> qcfl[N],qcfr[N];
int cf[N];
void work2(){
for(int i=1;i<=n;i++)
qcfl[i].clear(),qcfr[i].clear(),cf[i]=0;
for(int i=1;i<=cnt;i++){
qcfl[q[i].l].push_back(q[i]);
qcfr[q[i].r+1].push_back(q[i]);
}
for(int v=1;v<=n;v++){
for(auto i:qcfl[v]){
int x=i.x,y=i.y,z=i.z;
int dp=dep[i.v]+y;
while(dp<=mxdep){
cf[dp]+=z;dp+=x;
}
}
for(auto i:qcfr[v]){
int x=i.x,y=i.y,z=i.z;
int dp=dep[i.v]+y;
while(dp<=mxdep){
cf[dp]-=z;dp+=x;
}
}
val[dfnx[v]]+=cf[dep[dfnx[v]]];
}
}
int query(int v){
int ans=val[v];
int ql=dfn[v],qr=dfn[v]+siz[v]-1;
int bl=(ql-1)/len+1;
for(int i=1;i<=Std2;i++)
ans+=sum[bl][i][dep[v]%i];
for(int i=1;i<=cnt;i++){
if(q[i].l<=ql&&ql<=q[i].r){
ans+=(((dep[v]-dep[q[i].v])%q[i].x)==q[i].y)?(q[i].z):(0);
}
}
return ans;
}
void solve(){
for(int i=1;i<=Q;i++){
int opt=read(),v=read();
if(opt==1){
int x=read(),y=read(),z=read();
if(x<=Std2){
work1(v,x,y,z);
}else{
q[++cnt]={v,x,y,z,dfn[v],dfn[v]+siz[v]-1};
if(cnt==Std1){
work2();
cnt=0;
}
}
}else{
int ans=query(v);
printf("%d\n",ans);
}
}
}
int main(){
// freopen("in","r",stdin);
// freopen("out","w",stdout);
n=read(),Q=read();
for(int i=2;i<=n;i++){
int x=read();
add(x,i),add(i,x);
}
init();
solve();
return 0;
}
根号分治
x \(\ge\) lim 修改不超过 \(\sqrt n\) 次 分块暴力修改
x \(<\) lim 维护 \(sum[i][j]\) 为 从 \(j\) 开始跳,跳\(i\)步的和.
查询时 暴力枚举\(x\),设 k 为跳的步数 \(l=x*k_{1}+b_{1}\) , \(r=x*k_{2}-b_{2}\) 两者 \(k\) 相同 利用前缀和直接查询,否则可以查询 \(k_{1}到k_{2}-1\) 两个块在减去在 \(l\) 处多加的,加上在 \(r\) 处 少加的.
要初始化分块的 \(add\) 数组.
好像不取模能过
Code
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=2e5+5;
const int mod=1e9+7;
const int Std1=550;
const int Std2=150;
inline int read(){
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
inline int add(int x,int y){
return (x+y>mod)?(x+y-mod):(x+y);
}
inline int del(int x,int y){
return (x-y<0)?(x-y+mod):(x-y);
}
int n,m,len;
int a[N];
int ad[N],sum[Std1+5][Std2+5];
int L[N],R[N],bl[N];
inline void work1(int x,int y,int z){
for(int i=y;i<=n;i+=x)
a[i]=add(a[i],z),ad[bl[i]]=add(ad[bl[i]],z);
}
inline void work2(int x,int y,int z){
for(int i=y%x;i<x;i++)
sum[x][i]=add(sum[x][i],z);
}
inline int query1(int l,int r){
int bll=bl[l],blr=bl[r];
int ans=0;
if(bll==blr){
for(int i=l;i<=r;i++)
ans=add(ans,a[i]);
return ans;
}
for(int i=l;i<=R[bll];i++)
ans=add(ans,a[i]);
for(int i=L[blr];i<=r;i++)
ans=add(ans,a[i]);
for(int i=bll+1;i<=blr-1;i++)
ans=add(ans,ad[i]);
return ans;
}
int query2(int l,int r){
int ans=0;
for(int i=1;i<=Std2;i++){
int bl=l/i,br=r/i;
if(bl==br)
ans=add(ans,del(sum[i][r%i],sum[i][l%i-1]));
else
ans=add(ans,add(1ll*(br-bl)*sum[i][i-1]%mod,del(sum[i][r%i],sum[i][l%i-1])));
}
return ans;
}
void solve(){
while(m--){
int opt=read();
if(opt==1){
int x=read(),y=read(),z=read();
// work1(x,y,z);
(x>Std2)?work1(x,y,z):work2(x,y,z);
}else{
int l=read(),r=read();
// printf("%d\n",query1(l,r));
printf("%d\n",add(query1(l,r),query2(l,r)));
}
}
}
int main(){
// freopen("in","r",stdin);
// freopen("out","w",stdout);
n=read(),m=read();
len=sqrt(n);
for(int i=1;i<=(n-1)/len+1;i++)
L[i]=R[i-1]+1,R[i]=i*len;
for(int i=1;i<=n;i++)
bl[i]=(i-1)/len+1;
for(int i=1;i<=n;i++)
a[i]=read(),ad[bl[i]]=add(ad[bl[i]],a[i]);
solve();
return 0;
}
Code
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int N=1e6+5;
const int mod=10007;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
ll ksm(int a,int b){
ll ans=1;
while(b){
if(b&1)
ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
struct Node{
int to,next;
}e[N<<1];
int lk[N],ntot;
void add(int x,int y){
e[++ntot]={y,lk[x]};
lk[x]=ntot;
}
int n,k;
ll st[155][155];
ll fac[N];
int dp[N][155];
void dfs(int x,int fa){
dp[x][0]=1;
for(int i=lk[x];i;i=e[i].next){
int y=e[i].to;
if(y==fa)
continue;
dfs(y,x);
for(int j=0;j<=k;j++)
dp[x][j]=((dp[x][j]+dp[y][j])%mod+dp[y][j-1])%mod;
}
}
int f[N][155];
void dfs1(int x,int fa){
if(x==1){
for(int i=0;i<=k;i++)
f[x][i]=dp[x][i]%mod;
}else{
for(int i=1;i<=k;i++){
if(i-2>=0){
f[x][i]=(((f[fa][i]+f[fa][i-1])%mod-2ll*dp[x][i-1]%mod+mod*2ll)%mod-dp[x][i-2]%mod+mod*2ll)%mod;
}else{
f[x][i]=((f[fa][i]+f[fa][i-1])%mod-2ll*dp[x][i-1]%mod+mod)%mod;
}
}
f[x][0]=f[fa][0]%mod;
}
for(int i=lk[x];i;i=e[i].next){
int y=e[i].to;
if(y==fa)
continue;
dfs1(y,x);
}
}
signed main(){
// freopen("in","r",stdin);
// freopen("out","w",stdout);
n=read(),k=read();
for(int i=1;i<=n-1;i++){
int x=read(),y=read();
add(x,y),add(y,x);
}
st[0][0]=1,fac[0]=1;
for(int i=1;i<=k+1;i++){
for(int j=1;j<=i;j++){
st[i][j]=(1ll*st[i-1][j-1]+1ll*j*1ll*st[i-1][j]%mod)%mod;
}
}
for(ll i=1;i<=k;i++)
fac[i]=1ll*fac[i-1]*i%mod;
dfs(1,0),dfs1(1,0);
ll inv2=ksm(2,mod-2)%mod;
for(int i=1;i<=n;i++){
long long ans=0;
for(int j=1;j<=k;j++){
ans=(ans+1ll*fac[j]%mod*1ll*st[k][j]%mod*1ll*f[i][j]%mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}
<\details>