最近的一些小题题
懒得一个一个发了...
一起搞一下吧23333
(其实你这个菜b就是懒得写详细题解承认吧
bzoj4668
每次link一个递增的边权,查询两点边权最小值。
并查集按秩合并乱搞一下...本来想LCT的但是看见网上LCT被卡了一遍
#include<bits/stdc++.h> const int maxn = 500010; using namespace std; int f[maxn],depth[maxn],val[maxn],rank[maxn]; int lastans,opt; int n,m; int dfn; inline int find(int x) { if(x == f[x])return x; int res = find(f[x]); depth[x] = depth[f[x]] + 1; return res; } inline int solve(int x,int y) { int ret = -1; while(x != y) { if(depth[x] < depth[y]){x ^= y, y ^= x, x ^= y;} ret = max(ret,val[x]); x = f[x]; } return ret; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)f[i] = i; while(m--) { int x,y; scanf("%d%d%d",&opt,&x,&y); x ^= lastans,y ^= lastans; if(opt == 0) { ++dfn; int fx = find(x),fy = find(y); if(rank[fx] >= rank[fy]) { f[fy] = fx; val[fy] = dfn; if(rank[fx] == rank[fy])++rank[fx]; } else { f[fx] = fy; val[fx] = dfn; } } else { int fx = find(x),fy = find(y); if(fx != fy) { lastans = 0; puts("0"); } else { lastans = solve(x,y); printf("%d\n",lastans); } } } }
bzoj2006
一个序列(n<=500000),要求选定k个不同区间,使得区间长度在L,R之间,并使得k个区间和之和最大,输出这个最大值。
本来思考了很长时间dp...
结果发现是主席树乱搞
每一个子序列的权值和可以转化为两个前缀和之差。我们考虑以每一个位置为结尾的子序列,它的权值和可以看作是以该位置为结尾的前缀和减去它前面的某个前缀和。
那么想要这个子序列的权值和尽量大,那么就要前面的那个前缀和尽可能小。如果数目不够,就第2小。再不够,就第3小。
于是我们维护一个全局堆,分别表示以每个位置为结尾的最大子序列权值和,每次取出堆顶时再放进堆中一个结尾位置相同的第k+1大的权值和。
这样k次就能出解。
这要求我们能够快速求出区间第k小,利用可持久化线段树即可。
时间复杂度O(klogn).
#include<bits/stdc++.h> #define int long long using namespace std; const int maxn = 500010; const int lima = -500000005; const int limb = 500000005; int n,k,L,R; int a[maxn]; int s[maxn],ans; inline int read() { int x = 0,f = 1; char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch=getchar())x = 10 * x + ch-'0'; return x*f; } namespace SegTree { int ls[20000005] ,rs[20000005] , root[maxn]; int val[20000005] ,SIZE; inline void insert(int pre,int &cur,int l,int r,int va) { cur = ++SIZE; ls[cur] = ls[pre], rs[cur] = rs[pre], val[cur] = val[pre] + 1; if(l == r)return; int mid = (l+r) >> 1; if(va <= mid) insert(ls[pre],ls[cur],l,mid,va); else insert(rs[pre],rs[cur],mid+1,r,va); } inline int query(int cur,int pre,int l,int r,int k) { if(val[pre] - val[cur] < k) return 1e9; if(l >= r)return l; int x = val[ls[pre]] - val[ls[cur]]; int mid = (l+r) >> 1; if(k <= x)return query(ls[cur],ls[pre],l,mid,k); else return query(rs[cur],rs[pre],mid+1,r,k-x); } } struct data { int n,k; int v; bool operator < (const data &b)const{return v < b.v;} }; priority_queue<data> q; signed main() { using namespace SegTree; n=read(),k=read(),L=read(),R=read(); insert(0,root[0],lima,limb,0); for(int i=1;i<=n;i++)s[i] = s[i-1] + read(); for(int i=1;i<=n;i++)insert(root[i-1],root[i],lima,limb,s[i]); for(int i=L;i<=n;i++) { int aR = i - L ,aL = i - R - 1; int tem; if(aL < 0)tem = query(0,root[aR],lima,limb,1); else tem = query(root[aL],root[aR],lima,limb,1); q.push((data){i,1,s[i] - tem}); } data temp; while(k--) { temp = q.top(); q.pop(); ans += temp.v; int aR = temp.n - L ,aL = temp.n - R - 1; int tem; if(aL < 0)tem = query(0,root[aR],lima,limb,temp.k+1); else tem = query(root[aL],root[aR],lima,limb,temp.k+1); q.push((data){temp.n,temp.k+1,s[temp.n]-tem}); } printf("%lld\n",ans); }
bzoj3698
XWW是个影响力很大的人,他有很多的追随者。这些追随者都想要加入XWW教成为XWW的教徒。但是这并不容易,需要通过XWW的考核。
XWW给你出了这么一个难题:XWW给你一个N*N的正实数矩阵A,满足XWW性。
称一个N*N的矩阵满足XWW性当且仅当:(1)A[N][N]=0;(2)矩阵中每行的最后一个元素等于该行前N-1个数的和;(3)矩阵中每列的最后一个元素等于该列前N-1个数的和。
现在你要给A中的数进行取整操作(可以是上取整或者下取整),使得最后的A矩阵仍然满足XWW性。同时XWW还要求A中的元素之和尽量大。
这种网格的东西...首选网络流源点S向每一行连一条容量为(a[i][n],a[i][n]+1)的边
每一列向汇点T连一条容量为(a[n][i],a[n][i]+1)的边
行i向列j连一条容量为(a[i][j],a[i][j]+1)的边
先跑一遍可行流,然后删SSTT跑最大流
#include<bits/stdc++.h> const int inf = 1000000000; using namespace std; int n,tot; const int maxn = 600; double a[maxn][maxn]; int first[100005],to[100005*2],next[100005*2],caps[100005*2],cnt = 1; int dis[maxn],ind[maxn]; int S,T,SS,TT,ans; queue<int> q; inline void add(int u,int v,int c) { to[++cnt] = v; next[cnt] = first[u]; first[u] = cnt; caps[cnt] = c; } inline void ins(int u,int v,int c){add(u,v,c),add(v,u,0);} inline int bfs(int s,int t) { for(int i=1;i<=TT;i++) dis[i] = -1; dis[s] = 0;q.push(s); while(!q.empty()) { int now = q.front();q.pop(); for(int i=first[now];i;i=next[i]) { if(caps[i] && dis[to[i]] == -1) { dis[to[i]] = dis[now] + 1; q.push(to[i]); } } } return dis[t] != -1; } inline int dfs(int u,int t,int flow) { if(u == t)return flow; int w,used = 0; for(int i=first[u];i;i=next[i]) if(dis[to[i]] == dis[u] + 1) { w = flow - used ,w = dfs(to[i],t,min(w,caps[i])); caps[i] -= w; caps[i^1] += w; used += w; if(used == flow)return flow; } return used; } int dinic(int s,int t) { ans = 0; while(bfs(s,t))ans += dfs(s,t,inf); return ans; } int main() { scanf("%d",&n); S=2*n+1;T=S+1;SS=T+1;TT=SS+1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lf",&a[i][j]); for(int i=1;i<n;i++) { if(a[i][n]!=(int)a[i][n])ins(S,i,1); ind[S]-=(int)a[i][n];ind[i]+=(int)a[i][n]; } for(int i=1;i<n;i++) { if(a[n][i]!=(int)a[n][i]) ins(i+n,T,1); ind[i+n]-=(int)a[n][i];ind[T]+=(int)a[n][i]; } for(int i=1;i<n;i++) for(int j=1;j<n;j++) { if(a[i][j]!=(int)a[i][j]) ins(i,j+n,1); ind[i]-=(int)a[i][j];ind[j+n]+=(int)a[i][j]; } for(int i=1;i<=TT;i++) if(ind[i]>0){tot+=ind[i];ins(SS,i,ind[i]);} else ins(i,TT,-ind[i]); ins(T,S,inf); dinic(SS,TT); if(tot!=ans){printf("No");return 0;} ans=0; dinic(S,T); printf("%d",ans*3); return 0; }
bzoj1409
计算$$p^{Fib_i}(mod q)$$
欧拉定理搞一下
预处理$Fib_i % phi(q)$
然后快速幂即可
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> #include<queue> #define inf 2139062143 #define ll long long #define MAXN 100100 using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } ll p[MAXN],ntp[MAXN],cnt,n,m,mod,T,m1; struct mat {ll num[2][2];}; mat mul(mat x,mat y) { mat res; memset(res.num,0,sizeof(res.num)); for(ll i=0;i<2;i++) for(ll j=0;j<2;j++) for(ll k=0;k<2;k++) (res.num[i][j]+=x.num[i][k]*y.num[k][j])%=m1; return res; } ll mat_q_pow(ll n) { if(n<=0) return 0; mat t,res; memset(res.num,0,sizeof(res.num)); t.num[0][0]=t.num[0][1]=t.num[1][0]=1,t.num[1][1]=0; res.num[0][0]=res.num[1][1]=1; while(n) { if(n&1) res=mul(res,t); t=mul(t,t); n>>=1; } return res.num[0][1]; } void mem() { for(ll i=2;i<MAXN;i++) { if(!ntp[i]) p[++cnt]=i; for(ll j=1;p[j]*i<MAXN;j++) { ntp[p[j]*i]=1; if(i%p[j]==0) break; } } } void phi(ll x) { ll res=x; for(ll i=1;p[i]*p[i]<=x;i++) if(x%p[i]==0) { res/=p[i],res*=p[i]-1; while(x%p[i]==0) x/=p[i]; } if(x!=1) res/=x,res*=x-1; m1=res; } ll num_q_pow(ll k,ll x) { ll res=1; while(x) { if(x&1) (res*=k)%=mod; (k*=k)%=mod,x>>=1; //cout<<n<<" "<<res<<endl; } return res; } int main() { T=read(),n=read(); mem(); while(T--) { m=read(),mod=read(); phi(mod); //cout<<m1<<endl; //cout<<mat_q_pow(m)<<endl; printf("%lld\n",num_q_pow(n,mat_q_pow(m))%mod); } }
bzoj2178
圆的面积并 模板
/************************************************************** Problem: 2178 User: Ez3real Language: C++ Result: Accepted Time:11208 ms Memory:1372 kb ****************************************************************/ #include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define fir first #define sec second #define eps (1e-13) #define maxn 1010 #define four 4.0 #define six 6.0 #define two 2.0 #define re register using namespace std; typedef pair<double,double>Pdd; typedef struct point{double x,y;}P; typedef struct circle { P o; double r; bool operator <(const circle &z)const{ return o.x<z.o.x;} Pdd getd(double x) { if(r<=fabs(o.x-x)) return Pdd(0,0);//相离 double dis=sqrt(r*r-(o.x-x)*(o.x-x)); return Pdd(o.y-dis,o.y+dis); //下、上交点 } }C; int n,no[maxn],cntt; double minl=10101010.0,maxr=-10101010.0; C cir[maxn],circ[maxn]; Pdd pd[maxn]; double D(P _1,P _2){return sqrt((_1.x-_2.x)*(_1.x-_2.x)+(_1.y-_2.y)*(_1.y-_2.y));} double getf(double x) {//此线在多个圆中的部分的并 double ans=0,last=-10101010; int cnt=0; for(re int i=1;i<=cntt;i++) { pd[++cnt]=circ[i].getd(x); cnt=(pd[cnt]==Pdd(0,0))?cnt-1:cnt; } sort(pd+1,pd+cnt+1); for(re int i=1;i<=cnt;i++) { if(pd[i].fir>last) ans+=pd[i].sec-pd[i].fir,last=pd[i].sec; else if(pd[i].sec>last) ans+=pd[i].sec-last,last=pd[i].sec; } //printf("***%.8lf %.8lf***",x,ans); return ans; } inline double getsim(double l,double r,double fl,double fm,double fr){return ((r-l)/six)*(fl+four*fm+fr);} double simpson(double l,double m,double r,double fl,double fm,double fr) {//是对f(x)表示直线x在圆内的部分的总长度这个函数求积分 double lm=(l+m)/two,rm=(m+r)/two,flm=getf(lm),frm=getf(rm); double lans=getsim(l,m,fl,flm,fm),rans=getsim(m,r,fm,frm,fr),totans=getsim(l,r,fl,fm,fr); //printf("%.8lf %.8lf %.8lf %.8lf\n",l,r,lans+rans,totans);system("pause"); if(fabs(lans+rans-totans)<=eps)return totans; else return simpson(l,lm,m,fl,flm,fm)+simpson(m,rm,r,fm,frm,fr); } int main() { memset(no,0,sizeof(no)); scanf("%d",&n); for(re int i=1;i<=n;i++) { scanf("%lf%lf%lf",&cir[i].o.x,&cir[i].o.y,&cir[i].r); if(minl>cir[i].o.x-cir[i].r)minl=cir[i].o.x-cir[i].r; if(maxr<cir[i].o.x+cir[i].r)maxr=cir[i].o.x+cir[i].r; } sort(cir+1,cir+n+1); for(re int i=1;i<=n;i++) { if(no[i])continue; for(int j=i+1;j<=n;j++) { if(no[j])continue; if(D(cir[i].o,cir[j].o)+cir[j].r<=cir[i].r) no[j]=1; } } for(re int i=1;i<=n;i++) if(!no[i])circ[++cntt]=cir[i]; double ans=simpson(minl,(minl+maxr)/two,maxr,0,getf((minl+maxr)/two),0); printf("%.3lf",ans); return 0; }
bzoj4621
考虑对结束后的数组dp,令dp[i][j]表示到第i位,操作了j次的方案;由于次数限制,所以对于每一个数字段最多操作一次。考虑转移,假设第i位左右可以延伸到[l,r],那么枚举延伸的右端点k,显然dp[k][j]+=Σdp[p][j-1],l-1<=p<k。注意到有个问题就是如果数组段就是[i,i],那么操作数j不能加1,要特判。
#include<bits/stdc++.h> using namespace std; const int p = 1e9 + 7; int n,k; int a[510]; int dp[510][510]; int l,r,j,cur; //(l,r) int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%d",&a[i]); memset(dp,0,sizeof(dp));dp[0][0] = 1; for(int i=1;i<=n;i++) { for(l = i;a[l-1]<a[i] && l>1;l--); for(r = i;a[r+1]<a[i] && r<n;r++); (dp[i][k] += dp[i-1][k]) %= p; for(int opt = k;opt;opt--) { for(j=l,cur = dp[l-1][opt-1];j<=r;j++) { (dp[j][opt]+=cur) %= p; (cur += dp[j][opt-1]) %= p; } (dp[i][opt-1] += dp[i-1][opt-1]) %= p; dp[i][opt] = (dp[i][opt] - dp[i-1][opt-1] + p)%p; } } int sigma = 0; for(int i=0;i<=k;i++)(sigma += dp[n][i]) %= p; printf("%d\n",sigma); }
bzoj4108
上下界
1.S -> i的出点 容量1,费用0
2.i的入点 -> T 容量1,费用0
3.i的出点 -> 0的入点 容量m,费用0
4.0的入点 -> 0的出点 容量m,费用0
5.对于边(i,j)长度为len,i -> j 容量∞,费用0
#include <cstdio> #include <cstring> #include <queue> #define inf 0x3f3f3f3f using namespace std; queue<int> q; int head[300] , to[100000] , val[100000] , cost[100000] , next[100000] , cnt = 1 , s , t , dis[300] , from[300] , pre[300]; void add(int x , int y , int v , int c) { to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt; to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt; } bool spfa() { int x , i; memset(dis , 0x3f , sizeof(dis)); memset(from , -1 , sizeof(from)); dis[s] = 0 , q.push(s); while(!q.empty()) { x = q.front() , q.pop(); for(i = head[x] ; i ; i = next[i]) if(val[i] && dis[to[i]] > dis[x] + cost[i]) dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i , q.push(to[i]); } return ~from[t]; } int mincost() { int ans = 0 , i , k; while(spfa()) { k = inf; for(i = t ; i != s ; i = from[i]) k = min(k , val[pre[i]]); ans += k * dis[t]; for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k; } return ans; } int main() { int n , k , i , j , x; scanf("%d%d" , &n , &k); s = 2 * n + 2 , t = 2 * n + 3 , add(0 , 1 , k , 0); for(i = 2 ; i <= n + 1 ; i ++ ) scanf("%d" , &x) , add(1 , i , inf , x) , add(s , i + n , 1 , 0) , add(i , t , 1 , 0) , add(i + n , 0 , inf , 0); for(i = 2 ; i <= n ; i ++ ) for(j = i + 1 ; j <= n + 1 ; j ++ ) scanf("%d" , &x) , add(i + n , j , inf , x); printf("%d\n" , mincost()); return 0; }
bzoj3473
广义SAM dp一下
#include<bits/stdc++.h> #define LL long long using namespace std; const int maxn = 2000010; int n,q; char ch[maxn]; string str[200010]; struct SAM { int tr[maxn][26],fa[maxn],mx[maxn],len[maxn],vis[maxn],c[maxn]; int sum[maxn]; int last,p,np,q,nq,cnt,rt; SAM(){last = ++cnt; rt = 1;} inline void extend(int c) { p = last, np = last = ++cnt, len[np] = len[p] + 1; while(!tr[p][c] && p) tr[p][c] = np, p = fa[p]; if(!p) fa[np] = rt; else { q = tr[p][c]; if(len[q] == len[p] + 1) fa[np] = q; else { nq = ++cnt; len[nq] = len[p] + 1; memcpy(tr[nq],tr[q],sizeof(tr[q])); fa[nq] = fa[q]; fa[q] = fa[np] = nq; while(tr[p][c] == q) tr[p][c] = nq,p = fa[p]; } } } inline void dfs(int x) { if(x == rt || vis[x])return; vis[x] = 1;dfs(fa[x]);sum[x] += sum[fa[x]]; } }sam; int main() { //freopen("data1.in","r",stdin); //freopen("data1.out","w",stdout); scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { scanf("%s",ch); int LEN = strlen(ch); str[i] = (string)ch; for(int j=0;j<LEN;j++) sam.extend(ch[j]-'a'); sam.last = sam.rt; } for(int i=1;i<=n;i++) { int LEN = str[i].length(); int cur = sam.rt,now = i; for(int j=0;j<LEN;j++) { cur = sam.tr[cur][str[i][j]-'a']; int x=cur; while(x && sam.vis[x] != now)sam.vis[x] = now,sam.c[x]++,x = sam.fa[x]; } } for(int i=1;i<=sam.cnt;i++)sam.vis[i] = 0; for(int i=1;i<=sam.cnt;i++) if(sam.c[i] >= q)sam.sum[i] = sam.len[i] - sam.len[sam.fa[i]]; for(int i=1;i<=sam.cnt;i++)sam.dfs(i); for(int i=1;i<=n;i++) { int cur = 1,LEN = str[i].length();LL ans = 0LL; for(int j=0;j<LEN;j++) cur = sam.tr[cur][str[i][j]-'a'],ans += sam.sum[cur]; printf("%lld ",ans); } }
bzoj1833
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
数位乱搞
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #include<stack> using namespace std; long long dp[11],ans[11]; long long a,b; long long calc(long long x) { long long t=1; while(x>0) {t*=10;x--;} return t; } long long work(long long x) { long long t=1,k=0; while(t<=x) {t*=10;k++;} t/=10;k--; while(t>0) { long long tmp=(x/t)%10; dp[0]+=x/(t*10)*calc(k); if(tmp==0) dp[0]-=calc(k)-x%t-1; else dp[tmp]+=(x/(t*10))*calc(k)+x%t+1; for(long long i=1;i<tmp;i++) { dp[i]+=(x/(t*10)+1)*calc(k); } for(long long i=tmp+1;i<10;i++) { dp[i]+=(x/(t*10))*calc(k); } t/=10;k--; } } int main() { scanf("%lld%lld",&a,&b); work(b); for(long long i=0;i<10;i++) ans[i]=dp[i]; memset(dp,0,sizeof(dp)); work(a-1); for(long long i=0;i<9;i++) printf("%lld ",ans[i]-dp[i]); printf("%lld\n",ans[9]-dp[9]); }
bzoj4212
Trie树跑一下主席树统计一下
orz
#include<bits/stdc++.h> #define LL long long using namespace std; const int maxn = 2050 , TRIENODE = 2000010 , MAXNODE = (maxn << 8); int n,m,k,ans; int la,ra,lb,rb; char str[TRIENODE]; inline void GetSTR() { char ch; while(!(((ch=getchar())>='a')&&(ch<='z'))); k=1;str[1]=(ch-'a'+ans)%26; while(((ch=getchar())>='a')&&(ch<='z'))str[++k]=(ch-'a'+ans)%26; } int pa[maxn],pb[maxn],first[TRIENODE],to[maxn],next[maxn],cnt; inline void add(int u,int v){to[++cnt]=v,next[cnt]=first[u],first[u]=cnt;} struct Trie { int tr[TRIENODE][26],st[TRIENODE],ed[TRIENODE],SIZE,dfn,rt; Trie(){rt = 0;} inline int extend() { int now = 0; for(int i=1;i<=k;i++) { int p = str[i]; if(!tr[now][p]) tr[now][p] = ++SIZE; now = tr[now][p]; } return now; } inline int dnetxe() { int now = 0; for(int i=k;i;i--) { int p = str[i]; if(!tr[now][p]) tr[now][p] = ++SIZE; now = tr[now][p]; } return now; } inline void dfs(int x) { st[x] = ++dfn; for(int i=0;i<26;i++) if(tr[x][i]) dfs(tr[x][i]); ed[x] = dfn; } inline void query() { int x=0; for(int i=1;i<=k;i++) { int p=str[i]; if(!tr[x][p]){la=ra=0;return;} x=tr[x][p]; } la=st[x],ra=ed[x]; } inline void yreuq() { int x=0; for(int i=k;i;i--) { int p=str[i]; if(!tr[x][p]){lb=rb=0;return;} x=tr[x][p]; } lb=st[x],rb=ed[x]; } }A,B; namespace ChairmanTree { int root[TRIENODE],ls[MAXNODE],rs[MAXNODE],val[MAXNODE],sz; inline void insert(int &cur,int l,int r,int pre,int va) { cur = ++sz; val[cur] = val[pre] + 1; if(l == r)return; ls[cur] = ls[pre],rs[cur] = rs[pre]; int mid = (l + r) >> 1; if(va <= mid) insert(ls[cur],l,mid,ls[pre],va); else insert(rs[cur],mid+1,r,rs[pre],va); } inline int query(int x,int l,int r) { if(!x) return 0; if(lb <= l && r <= rb)return val[x]; int mid = (l+r) >> 1, ans = 0; if(lb <= mid)ans+=query(ls[x],l,mid); if(rb > mid)ans+=query(rs[x],mid+1,r); return ans; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { GetSTR(); pa[i] = A.extend(); pb[i] = B.dnetxe(); } A.dfs(A.rt),B.dfs(B.rt); int j; for(int i=1;i<=n;i++)add(A.st[pa[i]],B.ed[pb[i]]); for(int i=1;i<=A.dfn;i++) for(ChairmanTree::root[i]=ChairmanTree::root[i-1],j=first[i];j;j=next[j]) ChairmanTree::insert(ChairmanTree::root[i],1,B.dfn,ChairmanTree::root[i-1],to[j]); scanf("%d",&m); while(m --) { GetSTR();A.query(); GetSTR();B.yreuq(); if(la && lb) ans = ChairmanTree::query(ChairmanTree::root[ra],1,B.dfn)-ChairmanTree::query(ChairmanTree::root[la],1,B.dfn);else ans = 0; printf("%d\n",ans); } }
bzoj1316
n个点带权有根树 每次询问是否有一条长度为Len的路径
点分治裸题
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define N 10005 int n,x,y,z,m,sum,root; int q[N],ans[N]; int tot,point[N],nxt[N*2],v[N*2],c[N*2]; int size[N],big[N],d[N],deep[N]; bool vis[N]; void add(int x,int y,int z) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z; } void getroot(int x,int fa) { size[x]=1;big[x]=0; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa&&!vis[v[i]]) { getroot(v[i],x); size[x]+=size[v[i]]; big[x]=max(big[x],size[v[i]]); } big[x]=max(big[x],sum-size[x]); if (big[x]<big[root]) root=x; } void getdeep(int x,int fa) { deep[++deep[0]]=d[x]; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa&&!vis[v[i]]) { d[v[i]]=d[x]+c[i]; getdeep(v[i],x); } } int findl(int l,int r,int k) { int ans=0; while (l<=r) { int mid=(l+r)>>1; if (deep[mid]==k) ans=mid,r=mid-1; else if (deep[mid]<k) l=mid+1; else r=mid-1; } return ans; } int findr(int l,int r,int k) { int ans=-1; while (l<=r) { int mid=(l+r)>>1; if (deep[mid]==k) ans=mid,l=mid+1; else if (deep[mid]<k) l=mid+1; else r=mid-1; } return ans; } int calc(int x,int now,int k) { d[x]=now;deep[0]=0; getdeep(x,0); sort(deep+1,deep+deep[0]+1); int t=0; for (int i=1;i<=deep[0];++i) { if (deep[i]+deep[i]>k) break; int l=findl(i,deep[0],k-deep[i]); int r=findr(i,deep[0],k-deep[i]); t+=r-l+1; } return t; } void dfs(int x) { for (int i=1;i<=m;++i) ans[i]+=calc(x,0,q[i]); vis[x]=1; for (int i=point[x];i;i=nxt[i]) if (!vis[v[i]]) { for (int j=1;j<=m;++j) ans[j]-=calc(v[i],c[i],q[j]); sum=size[v[i]];root=0; getroot(v[i],0); dfs(root); } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<n;++i) { scanf("%d%d%d",&x,&y,&z); add(x,y,z),add(y,x,z); } for (int i=1;i<=m;++i) scanf("%d",&q[i]); big[0]=N; sum=n;root=0; getroot(1,0); dfs(root); for (int i=1;i<=m;++i) if (ans[i]) puts("Yes"); else puts("No"); }
bzoj3027
生成函数
#include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #include<vector> #define pb push_back #define mp make_pair #define xx first #define yy second #define rep(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;i++) #define dwn(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;i--) using namespace std; const int Size=1<<16; char buffer[Size],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,Size,stdin); tail=(head=buffer)+l; } if(head==tail) return -1; return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } typedef long long ll; typedef pair<int,int> pii; const int maxn=10000010; const int mod=2004; int n,F[maxn],G[maxn],l,r; int main() { n=read();l=read();r=read(); int *f=F,*g=G; int s=0;f[0]=1; rep(i,1,n) { int x=read(); rep(j,0,s+x) { if(j) (f[j]+=f[j-1])%=mod; g[j]=f[j]; if(j>x) g[j]=(g[j]-f[j-x-1]+mod)%mod; } s+=x; swap(f,g); } int ans=0; rep(i,l,r) (ans+=f[i])%=mod; printf("%d\n",ans); return 0; }
bzoj1641
求两个点之间最大路径的最小值
FLOYD
#include<bits/stdc++.h> using namespace std; const int inf = 2147483233; const int maxn = 310; int n,m,t; int gr[maxn][maxn]; int main() { scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)gr[i][j] = inf; for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); gr[u][v] = min(gr[u][v],w); } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) gr[i][j] = min(gr[i][j],max(gr[i][k],gr[k][j])); for(int i=1;i<=t;i++) { int u,v; scanf("%d%d",&u,&v); if(gr[u][v] == inf)puts("-1"); else printf("%d\n",gr[u][v]); } }
bzoj2120
带修改莫队入门题
调一年系列
#include<bits/stdc++.h> #define N 10005 using namespace std; int qid=0,tim=0,cx[1000005],res,block[N],ans[N],a[N]; struct ask{int l,r,t,id;}q[N]; struct chan{int x,y;}ch[1005]; int cmp(ask a,ask b) { if (block[a.l]==block[b.l]) { if (a.r==b.r) return a.t<b.t; else return a.r<b.r; }else return a.l<b.l; } void change(int now,int i) { if (ch[now].x>=q[i].l && ch[now].x<=q[i].r) { cx[a[ch[now].x]]--; if (cx[a[ch[now].x]]==0) res--; if (cx[ch[now].y]==0) res++; cx[ch[now].y]++; } swap(a[ch[now].x],ch[now].y); } int main() { int n,m,i; scanf("%d%d",&n,&m); int size=sqrt(n); for (i=1;i<=n;i++) scanf("%d",&a[i]),block[i]=(i-1)/size+1; for (i=1;i<=m;i++) { int l,r;char s[5]; scanf("%s%d%d",s,&l,&r); if (s[0]=='Q'){ q[++qid].l=l; q[qid].r=r; q[qid].id=qid; q[qid].t=tim; } else ch[++tim].x=l,ch[tim].y=r; } sort(q+1,q+qid+1,cmp); int l=0,r=0,now=0; for (i=1;i<=qid;i++) { while (l<q[i].l){cx[a[l]]--;if (cx[a[l]]==0) res--; l++;} while (l>q[i].l){l--;if (cx[a[l]]==0) res++; cx[a[l]]++;} while (r<q[i].r){r++;if (cx[a[r]]==0) res++; cx[a[r]]++;} while (r>q[i].r){cx[a[r]]--;if (cx[a[r]]==0) res--; r--;} while (now<q[i].t){now++;change(now,i);} while (now>q[i].t){change(now,i);now--;} ans[q[i].id]=res; } for (i=1;i<=qid;i++) printf("%d\n",ans[i]); }
bzoj4999
#include<bits/stdc++.h> using namespace std; const int maxn = 100010; const int MAXNODE = (maxn << 7); map<int,int> ma; int n,q; int first[maxn],to[maxn*2],next[maxn*2],cnt; int val[maxn]; inline void add(int u,int v){to[++cnt]=v,next[cnt]=first[u],first[u]=cnt;} int depth[maxn],size[maxn],top[maxn],pos[maxn],fa[maxn],dfn; inline void dfs1(int u) { size[u]=1; for(int i=first[u];i;i=next[i]) { if(to[i] == fa[u])continue; fa[to[i]] = u; depth[to[i]] = depth[u] + 1; dfs1(to[i]); size[u] += size[to[i]]; } } inline void dfs2(int u,int col) { pos[u] = ++dfn; top[u] = col; int k=0; for(int i=first[u];i;i=next[i]) if(to[i] != fa[u] && size[to[i]] > size[k])k=to[i]; if(!k) return; dfs2(k,col); for(int i=first[u];i;i=next[i]) if(to[i] != fa[u] && to[i] != k)dfs2(to[i],to[i]); } int ls[MAXNODE],rs[MAXNODE],root[MAXNODE],SZ,sum[MAXNODE]; inline void insert(int &cur,int l,int r,int ps,int va) { if(!cur) cur = ++SZ; sum[cur] += va; if(l == r)return; int mid = (l + r) >> 1; if(ps <= mid) insert(ls[cur],l,mid,ps,va); else insert(rs[cur],mid+1,r,ps,va); } inline int query(int cur,int l,int r,int ql,int qr) { if(!cur) return 0; if(ql <= l && r <= qr)return sum[cur]; int mid = (l + r) >> 1 , ans = 0; if(ql <= mid) ans += query(ls[cur],l,mid,ql,qr); if(qr > mid) ans += query(rs[cur],mid+1,r,ql,qr); return ans; } inline int get(int x,int y,int col) { int ans = 0; while(top[x] != top[y]) { if(depth[top[x]] < depth[top[y]])swap(x,y); ans += query(root[col],1,n,pos[top[x]],pos[x]); x = fa[top[x]]; } if(depth[x] > depth[y])swap(x,y); ans += query(root[col],1,n,pos[x],pos[y]); return ans; } int POS; char opt[5]; int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++)scanf("%d",&val[i]); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v),add(v,u); } dfs1(1),dfs2(1,1); for(int i=1;i<=n;i++) { if(!ma[val[i]]) ma[val[i]] = ++POS; insert(root[ma[val[i]]],1,n,pos[i],1); } int a,x,c; while(q--) { scanf("%s",opt); if(opt[0] == 'C') { scanf("%d%d",&a,&x); insert(root[ma[val[a]]],1,n,pos[a],-1); if(!ma[x])ma[x] = ++POS; insert(root[ma[x]],1,n,pos[a],1); val[a] = x; } else { scanf("%d%d%d",&a,&x,&c); if(!ma[c])puts("0"); else printf("%d\n",get(a,x,ma[c])); } } }
bzoj4025
神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。
二分图定义...md
可以考虑用LCT维护一个以删除时间为关键字的最大生成树
同时维护一个边的集合表示在这个集合中的边如果在图中则一定不是二分图(就用一个数组就好了_ (:зゝ∠) _)
由二分图的定义可知 二分图是没有奇环的图
然后对于那两种操作:
对于插入,如果边的两端点不连通,连边后一定不会形成环,直接link上
如果已经联通,加边后一定存在非树边.此时如果加边后会形成奇环,就把这条边加入上述集合
删除时候对于树边直接删除,非树边在集合中则直接从集合中删除
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define MAXN 100010 #define GET (ch>='0'&&ch<='9') #define MAXINT 0x3f3f3f3f using namespace std; int n,m,T,Top,cnt; int sta[MAXN<<1],top; int In[MAXN<<1],on[MAXN<<1]; struct splay { int ch[2],fa,minn,st,sum,val; bool rev; }tree[MAXN<<2]; inline void in(int &x) { char ch=getchar();x=0; while (!GET) ch=getchar(); while (GET) x=x*10+ch-'0',ch=getchar(); } struct edge { int u,v,w; }e[MAXN<<1]; struct Edge { int to; Edge *next; }E[MAXN<<2],*prev1[MAXN],*prev2[MAXN]; inline void insert1(int u,int v) {E[++Top].to=v;E[Top].next=prev1[u];prev1[u]=&E[Top];} inline void insert2(int u,int v) {E[++Top].to=v;E[Top].next=prev2[u];prev2[u]=&E[Top];} inline bool is_root(int x) { return tree[tree[x].fa].ch[0]!=x&&tree[tree[x].fa].ch[1]!=x; } inline void push_down(int x) { if (tree[x].rev) { tree[tree[x].ch[0]].rev^=1,tree[tree[x].ch[1]].rev^=1; swap(tree[x].ch[0],tree[x].ch[1]); } tree[x].rev=0; } inline void push_up(int x) { tree[x].minn=tree[x].val;tree[x].st=x;tree[x].sum=x>n; if (tree[x].ch[0]) { if (tree[tree[x].ch[0]].minn<tree[x].minn) tree[x].minn=tree[tree[x].ch[0]].minn,tree[x].st=tree[tree[x].ch[0]].st; tree[x].sum+=tree[tree[x].ch[0]].sum; } if (tree[x].ch[1]) { if (tree[tree[x].ch[1]].minn<tree[x].minn) tree[x].minn=tree[tree[x].ch[1]].minn,tree[x].st=tree[tree[x].ch[1]].st; tree[x].sum+=tree[tree[x].ch[1]].sum; } } inline void rot(int x) { int y=tree[x].fa,z=tree[y].fa,l,r; l=(tree[y].ch[1]==x);r=l^1; if (!is_root(y)) tree[z].ch[tree[z].ch[1]==y]=x; tree[tree[x].ch[r]].fa=y;tree[y].fa=x;tree[x].fa=z; tree[y].ch[l]=tree[x].ch[r];tree[x].ch[r]=y; push_up(y);push_up(x); } inline void Splay(int x) { top=0;sta[++top]=x; for (int i=x;!is_root(i);i=tree[i].fa) sta[++top]=tree[i].fa; while (top) push_down(sta[top--]); while (!is_root(x)) { int y=tree[x].fa,z=tree[y].fa; if (!is_root(y)) { if ((tree[y].ch[0]==x)^(tree[z].ch[0]==y)) rot(x); else rot(y); } rot(x); } } inline void access(int x) { for (int i=0;x;i=x,x=tree[x].fa) Splay(x),tree[x].ch[1]=i,push_up(x); } inline void make_root(int x) { access(x);Splay(x);tree[x].rev^=1; } inline void link(int x,int y) { make_root(x);tree[x].fa=y; } inline void cut(int x,int y) { make_root(x);access(y);Splay(y);tree[y].ch[0]=tree[x].fa=0;push_up(y); } inline void split(int x,int y) { make_root(x);access(y);Splay(y); } inline int find_root(int x) { /*access(x);Splay(x); while (tree[x].ch[0]) x=tree[x].ch[0];*/ for (access(x),Splay(x);tree[x].ch[0];x=tree[x].ch[0]); return x; } inline void ins(int x) { int u=e[x].u,v=e[x].v; if (u==v) {In[x]=1;cnt++;return;} if (find_root(u)!=find_root(v)) on[x]=1,link(u,x+n),link(v,x+n); else { split(u,v);int y=tree[v].st-n; if (e[y].w<e[x].w) { if (tree[v].sum&1^1) In[y]=1,cnt++; cut(e[y].u,y+n);cut(e[y].v,y+n);link(u,x+n);link(v,x+n); on[y]=0;on[x]=1; } else if (tree[v].sum&1^1) In[x]=1,cnt++; } } inline void del(int x) { if (on[x]) cut(e[x].u,x+n),cut(e[x].v,x+n); else if (In[x]) cnt--; } int main() { in(n);in(m);in(T);int s,t; for (int i=1;i<=n;i++) tree[i].val=tree[i].minn=MAXINT,tree[i].st=i; for (int i=1;i<=m;i++) { in(e[i].u);in(e[i].v);in(s);in(t);e[i].w=t; insert1(s,i);insert2(t,i); tree[i+n].val=tree[i+n].minn=t;tree[i+n].st=i+n;tree[i+n].sum=1; } for (int x=0;x<T;x++) { for (Edge *i=prev1[x];i;i=i->next) ins(i->to); for (Edge *i=prev2[x];i;i=i->next) del(i->to); puts(cnt?"No":"Yes"); } }
bzoj3932
主席树裸题
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 200005 #define maxm 8000005 using namespace std; int m,n,tot; int rt[maxn],ls[maxm],rs[maxm]; int f[maxn],fp[maxn]; ll cnt[maxm],sum[maxm]; struct data{int s,e,p,num;}a[maxn]; struct poi{int tim,val,flg;}b[maxn*2]; 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*10+ch-'0';ch=getchar();} return x*f; } inline bool cmpa(data x,data y){return x.p<y.p;} inline bool cmpb(poi x,poi y){return x.tim<y.tim;} inline void build(int &k,int l,int r) { k=++tot;sum[k]=cnt[k]=0; if (l==r) return; int mid=(l+r)>>1; build(ls[k],l,mid); build(rs[k],mid+1,r); } inline void update(int x,int &y,int l,int r,int v,int d) { y=++tot; cnt[y]=cnt[x]+d;sum[y]=sum[x]+(ll)f[v]*(ll)d; if (l==r) return; ls[y]=ls[x];rs[y]=rs[x]; int mid=(l+r)>>1; if (v<=mid) update(ls[x],ls[y],l,mid,v,d); else update(rs[x],rs[y],mid+1,r,v,d); } inline ll query(int k,int num,int l,int r) { if (num==cnt[k]) return sum[k]; if (l==r) return sum[k]/cnt[k]*num; int mid=(l+r)>>1; if (num<=cnt[ls[k]]) return query(ls[k],num,l,mid); else return sum[ls[k]]+query(rs[k],num-cnt[ls[k]],mid+1,r); } int main() { m=read();n=read(); F(i,1,m){a[i].s=read();a[i].e=read();a[i].p=read();a[i].num=i;} sort(a+1,a+m+1,cmpa); int sz=0; F(i,1,m) { if (i==1||a[i].p!=a[i-1].p) f[++sz]=a[i].p; fp[i]=sz; } F(i,1,m) { b[i*2-1]=(poi){a[i].s,fp[i],1}; b[i*2]=(poi){a[i].e+1,fp[i],-1}; } sort(b+1,b+m*2+1,cmpb); build(rt[0],1,n); int t=1; F(i,1,n) { int pre=rt[i-1],tmp=rt[i-1]; for(;t<=2*m&&b[t].tim==i;t++) { update(pre,tmp,1,n,b[t].val,b[t].flg); pre=tmp; } rt[i]=tmp; } ll pr=1; F(i,1,n) { ll xi=read(),ai=read(),bi=read(),ci=read(); ll ki=(ai*pr+bi)%ci+1; if (ki>cnt[rt[xi]]) pr=sum[rt[xi]]; else if (ki==0) pr=0; else pr=query(rt[xi],ki,1,n); printf("%lld\n",pr); } return 0; }
bzoj4566
#include<bits/stdc++.h> #define LL long long using namespace std; const int maxn = 400010; char s[maxn]; int c[maxn],size[maxn],hsh[maxn],laz[maxn]; namespace SAM { int fa[maxn],to[maxn][26],mx[maxn]; int last=1,rt=1,cnt=1; void extend(int c) { int q,nq; int p=last,np=last=++cnt; mx[np]=mx[p]+1;size[np]=1; for(;!to[p][c];p=fa[p])to[p][c]=np; if(!p) fa[np]=1; else { q=to[p][c]; if(mx[p] + 1 == mx[q])fa[np]=q; else { nq=++cnt; mx[nq]=mx[p]+1; fa[nq]=fa[q];fa[q]=fa[np]=nq; memcpy(to[nq],to[q],sizeof(to[nq])); for(;to[p][c] == q;p=fa[p])to[p][c]=nq; } } } } using namespace SAM; int main() { scanf("%s",s); for(int i=0;s[i];i++)extend(s[i]-'a'); scanf("%s",s); int p=1,len=0;LL ans=0; for(int i=1;i<=cnt;i++)c[mx[i]]++; for(int i=1;i<=cnt;i++)c[i]+=c[i-1]; for(int i=cnt;i>=1;i--)hsh[c[mx[i]]--]=i; for(int i=cnt;i>=1;i--)size[fa[hsh[i]]] += size[hsh[i]]; for(int i=0;s[i];i++) { int c=s[i]-'a'; if(to[p][c])len++,p=to[p][c]; else { while(p && !to[p][c])p=fa[p]; if(p) len=mx[p]+1,p=to[p][c]; else p=1,len=0; } ans+=(LL)size[p]*(len-mx[fa[p]]); laz[fa[p]]++; } for(int i=cnt;i>=1;i--) { int x=hsh[i];laz[fa[x]]+=laz[x]; ans+=(LL)laz[x]*size[x]*(mx[x]-mx[fa[x]]); } printf("%lld",ans); }