bzoj 4765 -- 分块+dfs序+树状数组:
bzoj4765
bzoj4766
bzoj4767
考虑分块。将1~n分成sqrt(n)块,对每个点记录它在每个块中的祖先个数,修改一个点时枚举每一块修改。
查询[l,r]时如果一个块在[l,r]中,直接将其加入答案。显然只剩下O(sqrt(n))个点。求出树的dfs序,用树状数组维护就可以O(logn)求出答案。
时间复杂度O(n*sqrt(n)*logn)
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 inline char nc(){ 7 static char buf[100000],*p1=buf,*p2=buf; 8 if(p1==p2){ 9 p2=(p1=buf)+fread(buf,1,100000,stdin); 10 if(p1==p2)return EOF; 11 } 12 return *p1++; 13 } 14 inline void Read(int& x){ 15 char c=nc(); 16 for(;c<'0'||c>'9';c=nc()); 17 for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc()); 18 } 19 #define ULL unsigned long long 20 #define ll long long 21 #define N 100010 22 #define SN 400 23 #define lowbit(x) x&-x 24 struct Edge{ 25 int t,nx; 26 }e[N<<1]; 27 ULL Sum[SN],c[N],p[N]; 28 ll k; 29 int i,j,n,m,Cnt,s[N][SN],t[SN],S,T,a[N],b[N],f[N],h[N],B[N],Num,Rt,x,y,z; 30 inline void Add(int x,int y){ 31 e[++Num].t=y;e[Num].nx=h[x];h[x]=Num; 32 } 33 inline void Update_c(int x,int y){ 34 for(;x<=n;x+=lowbit(x))c[x]+=y; 35 } 36 inline void Dfs(int x,int F){ 37 p[x]=a[x];b[x]=++m;if(a[x])Update_c(b[x],a[x]);t[B[x]]++; 38 for(int i=1;i<=Cnt;i++)s[x][i]=t[i]; 39 for(int i=h[x];i;i=e[i].nx) 40 if(e[i].t!=F){ 41 Dfs(e[i].t,x); 42 p[x]+=p[e[i].t]; 43 } 44 Sum[B[x]]+=p[x];f[x]=m;t[B[x]]--; 45 } 46 inline void Update(int x,int y){ 47 for(int i=1;i<=Cnt;i++)Sum[i]+=1ll*y*s[x][i]; 48 Update_c(b[x],y); 49 } 50 inline ULL Query_c(int l,int r){ 51 ULL Ans=0; 52 for(int i=r;i;i-=lowbit(i))Ans+=c[i]; 53 for(int i=l-1;i;i-=lowbit(i))Ans-=c[i]; 54 return Ans; 55 } 56 inline ULL Query(int l,int r){ 57 ULL Ans=0; 58 if(B[l]==B[r]){ 59 for(int i=l;i<=r;i++)Ans+=Query_c(b[i],f[i]); 60 return Ans; 61 } 62 for(int i=B[l]+1;i<B[r];i++)Ans+=Sum[i]; 63 for(int i=l;B[i]==B[l];i++)Ans+=Query_c(b[i],f[i]); 64 for(int i=r;B[i]==B[r];i--)Ans+=Query_c(b[i],f[i]); 65 return Ans; 66 } 67 char ss[40]; 68 int Len; 69 inline void Print(ULL x){ 70 if(x==0)putchar(48); 71 for(Len=0;x;x/=10)ss[++Len]=x%10; 72 for(;Len;)putchar(ss[Len--]+48);putchar('\n'); 73 } 74 int main() 75 { 76 Read(n);Read(T);S=sqrt((double)n); 77 for(i=1;i<=n;i++)B[i]=(i-1)/S+1;Cnt=B[n]; 78 for(i=1;i<=n;i++)Read(a[i]); 79 for(i=1;i<=n;i++){ 80 Read(x);Read(y); 81 if(x==0)Rt=y;else Add(x,y),Add(y,x); 82 } 83 Dfs(Rt,0); 84 while(T--){ 85 Read(z);Read(x);Read(y); 86 if(z&1)Update(x,y-a[x]),a[x]=y;else Print(Query(x,y)); 87 } 88 return 0; 89 }
bzoj 4766 -- 快速幂+快速乘
一个结论:
一个完全二分图的生成树个数为nm-1*mn-1
由于要爆long long,要用快速乘。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define ll long long 6 ll n,m,p,a,b; 7 inline ll Ch(ll x,ll y){ 8 ll Ans=0; 9 while(y){ 10 if(y&1)Ans=(Ans+x)%p; 11 x=(x<<1)%p; 12 y>>=1; 13 } 14 return Ans; 15 } 16 inline ll Pow(ll x,ll y){ 17 if(y==0)return 1; 18 ll Ans=Pow(x,y>>1); 19 if(y&1)return Ch(Ch(Ans,Ans),x); 20 return Ch(Ans,Ans); 21 } 22 int main() 23 { 24 scanf("%lld%lld%lld",&n,&m,&p); 25 a=Pow(n,m-1);b=Pow(m,n-1); 26 printf("%lld",Ch(a,b)); 27 }
bzoj4767 -- DP+容斥
对于每个障碍点,从原点到它要使用的两种操作的次数可以用解方程解出。
对于一个障碍点,假如它需要的操作次数分别是x,y,那么从原点到它的路径种数就是(x+y)!/(x!*y!)
将每个障碍点需要的两种操作次数作为坐标。
对障碍点按x排序一遍,令f[i]表示从原点到i号障碍点不经过任何障碍点的路径种数,那么得到DP方程:
f[i]=g(x[i],y[i])-Σf[j]*g(x[i]-x[j],y[i]-y[j]),j<i且y[j]<y[i]
其中g(i,j)表示从原点到(i,j)的方案数。
预处理出阶乘、逆元的阶乘就可以了。
时间复杂度O(n*logn)
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define N 510 7 #define Max 1000000 8 #define M 1000000007 9 struct Node{ 10 int x,y; 11 }a[N],A,B; 12 int i,j,k,n,m,x,y,f[N],J1[Max],J2[Max],Ni[Max],X,Y; 13 inline void Solve(int x,int y){ 14 int a1=B.x*y-x*B.y,a2=A.y*B.x-A.x*B.y; 15 if(a1%a2)return; 16 int Ax=a1/a2; 17 a1=A.x*y-A.y*x,a2=A.x*B.y-A.y*B.x; 18 if(a1%a2)return; 19 int Ay=a1/a2; 20 if(Ax<0||Ay<0)return; 21 if(i<Max&&(Ax>a[1].x||Ay>a[1].y))return; 22 a[++m].x=Ax;a[m].y=Ay; 23 } 24 inline bool Cmp(Node a,Node b){ 25 return a.x<b.x||(a.x==b.x&&a.y<b.y); 26 } 27 inline int Work(int x,int y){ 28 return (1ll*J1[x+y]*J2[x])%M*J2[y]%M; 29 } 30 int main() 31 { 32 scanf("%d%d%d%d%d%d%d",&X,&Y,&n,&A.x,&A.y,&B.x,&B.y); 33 for(J1[1]=J2[1]=Ni[1]=J1[0]=J2[0]=1,i=2;i<Max;i++)J1[i]=1ll*J1[i-1]*i%M,Ni[i]=1ll*(M-M/i)*Ni[M%i]%M,J2[i]=1ll*J2[i-1]*Ni[i]%M; 34 Solve(X,Y); 35 if(m==0){printf("0");return 0;} 36 for(i=1;i<=n;i++){ 37 scanf("%d%d",&x,&y);Solve(x,y); 38 if(x==X&&y==Y){printf("0");return 0;} 39 } 40 sort(a+1,a+m+1,Cmp); 41 for(i=1;i<=m;i++){ 42 f[i]=Work(a[i].x,a[i].y); 43 for(j=1;j<i;j++)if(a[j].y<=a[i].y)f[i]=(f[i]-1ll*f[j]*Work(a[i].x-a[j].x,a[i].y-a[j].y)%M)%M; 44 } 45 printf("%d",(f[m]+M)%M); 46 return 0; 47 }