http://acm.hdu.edu.cn/showproblem.php?pid=6604
Problem Description
Country A and B are at war. Country A needs to organize transport teams to deliver supplies toward some command center cities.
In order to ensure the delivery works efficiently, all the roads in country A work only one direction. Therefore, map of country A can be regarded as DAG( Directed Acyclic Graph ). Command center cities only received supplies and not send out supplies.
Intelligence agency of country B is credibly informed that there will be two cities carrying out a critical transporting task in country A.
As long as **any** one of the two cities can not reach a command center city, the mission fails and country B will hold an enormous advantage. Therefore, country B plans to destroy one of the n cities in country A and all the roads directly connected. (If a city carrying out the task is also a command center city, it is possible to destroy the city to make the mission fail)
Now country B has made q hypotheses about the two cities carrying out the critical task.
Calculate the number of plan that makes the mission of country A fail.Input
The first line contains a integer T (1≤T≤10), denoting the number of test cases.
In each test case, the first line are two integers n,m, denoting the number of cities and roads(1≤n≤100,000,1≤m≤200,000).
Then m lines follow, each with two integers u and v, which means there is a directed road from city u to v (1≤u,v≤n,u≠v).
The next line is a integer q, denoting the number of queries (1≤q≤100,000)
And then q lines follow, each with two integers a and b, which means the two cities carrying out the critical task are a and b (1≤a,b≤n,a≠b).
A city is a command center if and only if there is no road from it (its out degree is zero).Output
For each query output a line with one integer, means the number of plan that makes the mission of country A fail.Sample Input
2 8 8 1 2 3 4 3 5 4 6 4 7 5 7 6 8 7 8 2 1 3 6 7 3 2 3 1 3 2 2 1 2 3 1Sample Output
4 3 2 2
#include <bits/stdc++.h> using namespace std; const int maxn=2e5+10; int n,m,tim,dfn[maxn],repos[maxn],idom[maxn],fa[maxn],mi[maxn],f[maxn],semi[maxn],id[maxn],ans[maxn]; int d[maxn],lc[maxn][25],w[maxn],T=24; struct edge { int tot, head[maxn], next[maxn], to[maxn]; void clear() { tot = 0; for (int i = 0; i <= n; i++) head[i] = 0; } void add(int u, int v) { to[++tot] = v; next[tot] = head[u]; head[u] = tot; } }G,RG,NG,TR; void init(){ tim=0; G.clear();RG.clear();NG.clear();TR.clear(); memset(lc,0, sizeof(lc)); for (int i=1;i<=n;i++){ repos[i]=dfn[i]=idom[i]=fa[i]=ans[i]=0; mi[i]=semi[i]=f[i]=i; w[i]=0; } } void dfs1(int x) { dfn[x] = ++tim; repos[tim] = x; for (int i = G.head[x]; i; i = G.next[i]) if (!dfn[G.to[i]]) { fa[G.to[i]] = x; dfs1(G.to[i]); } } int find(int x) { if (x == f[x]) return x; int tmp = f[x]; f[x] = find(f[x]); if (dfn[semi[mi[tmp]]] < dfn[semi[mi[x]]]) mi[x] = mi[tmp]; return f[x]; } void dfs(int x) { for (int i = TR.head[x]; i; i = TR.next[i]) { int to = TR.to[i]; d[to] = d[x] + 1; lc[to][0] = x; ans[to] += ans[x] + 1;//记录虚点到该点的支配点个数 for (int j = 1;j<=T; j++) lc[to][j] = lc[lc[to][j - 1]][j - 1]; dfs(to); } } int lca(int x,int y) { if (d[x] > d[y]) swap(x, y); for (int i = T; i >= 0; i--) { if (d[lc[y][i]] >= d[x]) y = lc[y][i]; } if (x == y) return x; for (int i = T; i >= 0; i--) { if (lc[x][i] != lc[y][i]) { x = lc[x][i]; y = lc[y][i]; } } return lc[x][0]; } void work() { for (int i = n; i >= 2; i--) { int x = repos[i], tmp = n; for (int j = RG.head[x]; j; j = RG.next[j]) { if (!dfn[RG.to[j]]) continue; if (dfn[RG.to[j]] < dfn[x]) tmp = min(tmp, dfn[RG.to[j]]); else { find(RG.to[j]); tmp = min(tmp, dfn[semi[mi[RG.to[j]]]]); } } semi[x] = repos[tmp]; f[x] = fa[x]; NG.add(semi[x], x); x = repos[i - 1]; for (int j = NG.head[x]; j; j = NG.next[j]) { int y = NG.to[j]; find(y); if (semi[mi[y]] == semi[y]) idom[y] = semi[y]; else idom[y] = mi[y]; } } for (int i = 2; i <= n; i++) { int x = repos[i]; if (idom[x] != semi[x]) idom[x] = idom[idom[x]]; TR.add(idom[x], x); } d[1]=1; dfs(1); } int main() { int _; scanf("%d", &_); while (_--) { scanf("%d%d", &n, &m); n++; init(); for (int i = 1, v, u; i <= m; i++) { scanf("%d%d",&u, &v); u++;v++; swap(u, v); w[v]++; G.add(u, v); RG.add(v, u); } for (int i = 2; i <= n; i++) { if (!w[i]) { G.add(1,i); RG.add(i,1); } } dfs1(1); work(); int q, x, y; scanf("%d", &q); while (q--) { scanf("%d%d", &x, &y); x++; y++; printf("%d ", ans[x] + ans[y] - ans[lca(x, y)]); } } return 0; }
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int S=8; ll mult_mod(ll a,ll b,ll c) { a%=c; b%=c; ll ret=0,tmp=a; while (b) { if (b&1) { ret+=tmp; if (ret>c) { ret-=c; } } tmp<<=1; if (tmp>c) tmp-=c; b>>=1; } return ret; } ll pow_mod(ll a,ll n,ll mod) { ll ret=1; ll temp=a%mod; while (n) { if(n&1) { ret=mult_mod(ret,temp,mod); } temp=mult_mod(temp,temp,mod); n>>=1; } return ret; } bool check(ll a,ll n,ll x,ll t) { ll ret=pow_mod(a,x,n); ll last=ret; for (int i=1; i<=t; i++) { ret=mult_mod(ret,ret,n); if (ret==1&&last!=1&&last!=n-1) { return 1; } last=ret; } if (ret!=1) { return 1; } return 0; } bool Miller_Rabin(ll n) { if (n<2) { return 0; } if (n==2) { return 1; } if ((n&1)==0) { return 0; } ll x=n-1; ll t=0; while ((x&1)==0) { x>>=1; t++; } srand(time(NULL)); for (int i=0; i<S; i++) { ll a=rand()%(n-1)+1; if (check(a,n,x,t)) { return 0; } } return 1; } ll factor[100]; int tol; ll gcd(ll a,ll b) { if (!b) { return a; } return gcd(b,a%b); } ll pollard_rho(ll x,ll c) { ll i=1,k=2; srand(time(NULL)); ll x0=rand()%(x-1)+1; ll y=x0; while (1) { i++; x0=(mult_mod(x0,x0,x)+c)%x; ll d=gcd(y-x0,x); if (d!=1&&d!=x) { return d; } if (y==x0) { return x; } if (i==k) { y=x0; k+=k; } } } __int128 quick(__int128 a,__int128 b,__int128 p) { __int128 ret=1%p; while (b) { if (b&1) { ret=ret*a%p; } b>>=1; a=a*a%p; } return ret; } void findfac(ll n,ll k) { if (n==1) { return; } if (Miller_Rabin(n)) { factor[tol++]=n; return; } ll p=n; ll c=k; while (p>=n) { p=pollard_rho(p,c--); } findfac(p,k); findfac(n/p,k); } __int128 inv(__int128 a,__int128 p){ return quick(a,p-2,p); } int main() { ll t,p,prime; __int128 ans; scanf("%lld",&t); while (t--) { scanf("%lld",&p); for (ll i=p-1; i>=2; i--) { if (Miller_Rabin(i)) { prime=i; break; } } ans=p-1; for (__int128 i=p-1;i>prime;i--){ ans=ans*inv(i,p)%p; } printf("%lld ",(ll)ans); } }
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll N=200010; ll w[N],b[N],n,m; struct node{ ll num,sum; }t[N*4]; struct data{ ll num,rk,id; }a[N]; inline void build(ll rt,ll l,ll r) { t[rt].num = t[rt].sum = 0; if (l == r) { return; } ll mid = (l + r) >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); } inline void change(ll rt,ll pos,ll l,ll r) { if (l == r) { t[rt].num = 1; t[rt].sum = b[pos]; return; } ll mid = (l + r) >> 1; if (pos <= mid) { change(rt << 1, pos, l, mid); } else { change(rt << 1 | 1, pos, mid + 1, r); } t[rt].sum = t[rt << 1].sum + t[rt << 1 | 1].sum; t[rt].num = t[rt << 1].num + t[rt << 1 | 1].num; } inline ll query(ll rt,ll w,ll l,ll r) { if (l == r) { return t[rt].sum <= w ? t[rt].num : 0; } ll mid=(l+r)>>1; if (t[rt << 1].sum <= w) { return t[rt << 1].num + query(rt << 1 | 1, w - t[rt << 1].sum,mid+1,r); } else { return query(rt << 1, w, l, mid); } } inline bool cmp1(data a,data b) { return a.num < b.num; } inline bool cmp2(data a,data b) { return a.id < b.id; } int main() { int t; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%lld", &w[i]); a[i].id = i; a[i].num = w[i]; } sort(a + 1, a + n + 1, cmp1); for (int i = 1; i <= n; i++) { a[i].rk = i; b[i] = a[i].num; } sort(a + 1, a + n + 1, cmp2); build(1, 1, n); for (int i = 1; i <= n; i++) { printf("%lld ", i - query(1, m - w[i], 1, n) - 1); change(1, a[i].rk, 1, n); } printf(" "); } }
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> PI; const int maxn=5000; const int inf=0x3f3f3f3f; int a[maxn]; struct Min_Cost_Max_Flow{ struct edge{ int to,cap,cost,rev; edge(){}; edge(int _to,int _cap,int _cost,int _rev):to(_to),cap(_cap),cost(_cost),rev(_rev){}; }; vector<edge>E[maxn]; int h[maxn],n,d[maxn],preV[maxn],preE[maxn]; void init(int n){ this->n=n; for (int i=0;i<=n;i++){ E[i].clear(); h[i]=0; } } void add(int from,int to,int cap,int cost){ E[from].push_back(edge(to,cap,cost,E[to].size())); E[to].push_back(edge(from,0,-cost,E[from].size()-1)); } PI dijkstra(int s,int t,int f){ int cost=0,flow=0; for (int i=0;i<=n;i++){ h[i]=0; } while (f){ priority_queue<PI,vector<PI>,greater<PI> >q; for (int i=0;i<=n;i++){ d[i]=inf; } d[s]=0; q.push(make_pair(0,s)); while (!q.empty()){ PI now=q.top(); q.pop(); int v=now.second; if (d[v]<now.first){ continue; } for (int i=0;i<E[v].size();i++){ edge &e=E[v][i]; if (e.cap>0&&d[e.to]>d[v]+e.cost+h[v]-h[e.to]){ d[e.to]=d[v]+e.cost+h[v]-h[e.to]; preV[e.to]=v; preE[e.to]=i; q.push(make_pair(d[e.to],e.to)); } } } if (d[t]==inf)break; for (int i=0;i<=n;i++){ h[i]+=d[i]; } int d=f; for (int i=t;i!=s;i=preV[i]){ d=min(d,E[preV[i]][preE[i]].cap); } f-=d; flow+=d; cost+=d*h[t]; for (int i=t;i!=s;i=preV[i]){ edge &e=E[preV[i]][preE[i]]; e.cap-=d; E[i][e.rev].cap+=d; } } return make_pair(flow,cost); } }G; int main() { int t,k,n; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } G.init(2*n+2); int S = 0, T = 2 * n + 2; G.add(S, n * 2 + 1, k, 0); for (int i = 1; i <= n; i++) { G.add(n * 2 + 1, i, 1, 0); G.add(i, n + i, 1, -a[i]); G.add(n + i, T, 1, 0); } for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { if (a[i] <= a[j]) { G.add(n + i, j, 1, 0); } } } PI ans=G.dijkstra(S,T,inf); printf("%d ",-ans.second); } }
题意:要求把一个序列分成连续的k块(可以去掉后缀),使得权值和最大的那一块权值最小,求出这个最小值
思路:先求前缀和leftSum[],然后对前缀和离散化;
对leftSum[]排序并去重得到pre[];
设f[i]=前i个数最多能分成的块数;
二分答案,设答案为x;
则转移方程为f[i]=max(f[j])+1,leftSum[i]-leftSum[j]<=x,j<i
不能O(n^2)转移,想办法加速;
以离散化后的pre[]的rank为下标,f为权值建立线段树;
线段树需要实现单点修改、区间求最大值操作;
每次求f[i]时,令L=lower_bound(pre+1,pre+1+num,leftSum[i]-x),其中num为pre[]离散化后数字个数,
然后只需求得线段树[L,num]区间内的最大值_max,将f[i]更新为=_max+1即可,此时别忘了用新得到的f[i]去update线段树。
代码中注意一些小细节要处理好。
总时间复杂度为O(n*(logn)^2).
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+10; int tot; ll mx[maxn*4],b[maxn],dp[maxn],n,m,sum[maxn],a[maxn]; void build(int rt,int l,int r) { if (l == r) { mx[rt] = -1; return; } int mid=(l+r)>>1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); } void update(int rt,int l,int r,int p,ll val) { if (l == r) { mx[rt] = max(mx[rt], val); return; } int mid = (l + r) >> 1; if (p <= mid) update(rt << 1, l, mid, p, val); else update(rt << 1 | 1, mid + 1, r, p, val); mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); } int query(int rt,int l,int r,int L,int R) { if (L > R) return -1; if (L <= l && r <= R) { return mx[rt]; } int mid = (l + r) >> 1, ans = -1; if (L <= mid) ans = max(ans, query(rt << 1, l, mid, L, R)); if (R > mid) ans = max(ans, query(rt << 1 | 1, mid + 1, r, L, R)); return ans; } bool solve(ll mid) { build(1, 1, tot); update(1, 1, tot, lower_bound(b + 1, b + 1 + tot, 0) - b, 0); for (int i = 1; i <= n; i++) { int p = lower_bound(b + 1, b + 1 + tot, sum[i] - mid) - b; int p1 = lower_bound(b + 1, b + 1 + tot, sum[i]) - b; int tmp = query(1, 1, tot, p, tot); if (tmp == -1) dp[i] = -1; else dp[i] = tmp + 1; update(1, 1, tot, p1, dp[i]); if (dp[i] >= m) return 0; } return 1; } int main() { int _; scanf("%d", &_); while (_--) { scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum[i] = sum[i - 1] + a[i]; b[i] = sum[i]; } b[n + 1] = 0; sort(b + 1, b + 1 + n + 1); tot = unique(b + 1, b + n + 1 + 1) - (b + 1); ll l = -2e14, r = 2e14; while (l < r) { ll mid = (l + r) >> 1; if (solve(mid)) l = mid + 1; else r = mid; } printf("%lld ", l); } }