T1 水管
题解
很简单的一道题,别想复杂了
只要一边 \(dfs\) 即可
先将当前点的所有水量给出去,如果缺水就给出去负数
那么等到最后一个节点如果不是刚好合适,那么就把剩余水量回溯回来,无论正负
再如此给下一个连边的点
如果最后一个点刚好合适那么给下一个点的就是 \(0\)
实现很简单
诅咒不给SPJ的出题人!
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define N 200010
using namespace std;
int n,m,a[N],sum,f[N<<1],u[N<<1],v[N<<1];
bool vis[N];
vector<pii>g[N];
int dfs(int x,int fl){
vis[x] = true;
fl-=a[x];
int tmp = fl;
for(pii i : g[x]){
if(!vis[i.fi]){
tmp = dfs(i.fi,fl);
if(u[i.se]==x) f[i.se] = fl-tmp;
else f[i.se] = -(fl-tmp);
fl = tmp;
}
}
return fl;
}
int main(){
freopen("flow.in","r",stdin);
freopen("flow.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i = 1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
if(sum){
cout<<"Impossible";
return 0;
}
cin>>m;
for(int i = 1;i<=m;i++){
cin>>u[i]>>v[i];
g[u[i]].push_back({v[i],i});
g[v[i]].push_back({u[i],i});
}
for(int i = 1;i<=n;i++)
if(!vis[i])
if(dfs(i,0)){
cout<<"Impossible";
return 0;
}
cout<<"Possible\n";
for(int i = 1;i<=m;i++)
cout<<f[i]<<"\n";
return 0;
}
T2 宝藏
题解
两种做法,第一种是 \(\mathcal O(nm^2)\) ,第二种 \(\mathcal O(nm\log m)\)
第一种需要处理一个二阶前缀和,然后暴力遍历所有列的区间并用桶存下
每当桶里有值时花费 \(\mathcal O(n)\) 来用双指针计数处理行对应的个数
如下为第一种代码
#include<bits/stdc++.h>
#define N 100010
#define M 110
#define ll long long
using namespace std;
int n,m,k,suml[N],sumr[M],t[N*M];
ll ans;
ll query(int k){
ll res = 0,j = 1,l = 1;
for(int i = 1;i<=n;i++){
while(suml[i]-suml[l-1]>k&&l<=i) l++;
while(suml[i]-suml[j-1]>=k&&j<=i) j++;
res+=j-l;
}
return res;
}
int main(){
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
for(int i = 1;i<=n;i++){
string s;
cin>>s;
for(int j = 0;j<m;j++){
suml[i]+=(s[j]=='$');
sumr[j+1]+=(s[j]=='$');
}
}
for(int i = 1;i<=n;i++)
suml[i]+=suml[i-1];
for(int i = 1;i<=m;i++)
sumr[i]+=sumr[i-1];
for(int i = 1;i<=m;i++)
for(int j = i;j<=m;j++)
t[sumr[j]-sumr[i-1]]++;
for(int i = 0;i<=k;i++){
if(!t[i])continue;
ans+=query(k-i)*t[i];
}
cout<<ans;
return 0;
}
第二种做法
对于原矩阵维护一个二维前缀和和后缀和,这样宝藏的数目就可以在两个点对上统计贡献
枚举其中一个点对,用数据结构寻找另一个点即可
#include<cstdio>
#define N 100005
#define M 105
#define K 100005
using namespace std;
int n,m,k,cnt,f[N][M],g[N][M],a[N][M];
long long ans;
struct BIT
{
int v[M];
void modify(int x)
{
if (!x) ++v[0];
for (;x<M && x;x+=x&-x) ++v[x];
}
int query(int x)
{
int res=0;
for (;x;x-=x&-x) res+=v[x];
return res+v[0];
}
} s[K*3];
int main()
{
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
scanf("%d%d%d\n",&n,&m,&k);
for (int i=1;i<=n;++i,scanf("\n"))
for (int j=1;j<=m;++j)
if (getchar()=='$')
++f[i][j],++g[i][j],++cnt;
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j)
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
for (int i=n;i;--i) for (int j=m;j;--j)
g[i][j]+=g[i+1][j]+g[i][j+1]-g[i+1][j+1];
for (int i=0;i<=n;++i) for (int j=0;j<=m;++j)
a[i][j]=f[i][j]-g[i+1][j+1];
//if (cnt>100000) return printf("?"),0;
for (int i=1;i<=n;++i)
{
for (int j=0;j<m;++j)
s[a[i-1][j]+2*cnt].modify(j);
for (int j=1;j<=m;++j)
ans+=s[a[i][j]-k+2*cnt].query(j-1);
}
printf("%lld",ans);
}
T3 梦色之乡
题解
这题总共有三种做法
第一种,通过点分树来加速找重心的过程从而做到 \(\mathcal O(n\log^2 n)\) 的复杂度
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define N 1000010
using namespace std;
int n,m,now,dfn[N],siz[N],sz[N],weight[2],f[N],x,y,cnt,tot,dfncnt,dep[N],fa[N][20],que[N];
bool vis[N];
vector<int>g[N];
unordered_map<int,int>mp[N];
set<pii>s[N];
bool check(int x,int y){//判断x是否在y的子树内
return dfn[x]>=dfn[y]&&(dfn[x]<=dfn[y]+siz[y]-1);
}
void dfs(int x,int father){
siz[x] = 1;
dfn[x] = ++dfncnt;
dep[x] = dep[father]+1;
fa[x][0] = father;
for(int i = 1;i<=17;i++)
fa[x][i] = fa[fa[x][i-1]][i-1];
for(int i : g[x]){
if(i==father) continue;
dfs(i,x);
siz[x]+=siz[i];
s[x].insert({siz[i],i});
}
if(father) s[x].insert({n-siz[x],father});
}
int jump(int x,int y){
for(int i = 17;i>=0;i--)
if(dep[fa[x][i]]>=y)
x = fa[x][i];
return x;
}
int gt(int p){
if(check(p,x)||check(p,y))
return fa[p][0];
int u = 0,v = 0,newv = 0,r = 0,t = 0,newt = 0;
if(!check(x,p)){
u = fa[p][0];
v = n-siz[p];
newv = v-siz[x];
}else{
u = jump(x,dep[p]+1);
v = siz[u];
newv = siz[u]-siz[x];
}
if(!check(y,p)){
r = fa[p][0];
t = n-siz[p];
newt = t-siz[y];
}else{
r = jump(y,dep[p]+1);
t = siz[r];
newt = siz[r]-siz[y];
}
if(r==u) newv-=siz[y],r = 0;
if(u){
s[p].erase({v,u});
s[p].insert({newv,u});
}
if(r){
s[p].erase({t,r});
s[p].insert({newt,r});
}
int tmpwei = 0;auto tmp = s[p].end();
tmp--;
if((*tmp).fi<=(now/2)){
weight[tot++] = p;
if(((*tmp).fi==(now/2))&&(now%2==0))
weight[tot++] = (*tmp).se;
}else tmpwei = (*tmp).se;
if(u){
s[p].erase({newv,u});
s[p].insert({v,u});
}
if(r){
s[p].erase({newt,r});
s[p].insert({t,r});
}
return tmpwei;
}
void ddfs(int x,int father){
sz[x] = 1;f[x] = 0;
que[++cnt] = x;
for(int i : g[x]){
if(i==father||vis[i]) continue;
ddfs(i,x);
sz[x]+=sz[i];
f[x] = max(f[x],sz[i]);
}
}
int getrt(int x){
cnt = 0;
ddfs(x,0);
int tmp = que[1];
for(int i = 1;i<=cnt;i++){
int p = que[i];
f[p] = max(f[p],cnt-sz[p]);
if(f[p]<f[tmp]) tmp = p;
}
return tmp;
}
int build(int x){
int u = getrt(x);
vis[u] = 1;
for(int i : g[u]){
if(vis[i]) continue;
int v = build(i);
mp[u][i] = v;
}
return u;
}
signed main(){
freopen("dream.in","r",stdin);
freopen("dream.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i = 1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
int rt = build(1);
for(int i = 1;i<=m;i++){
cin>>x>>y;
if(dfn[y]<dfn[x]) swap(x,y);
if(check(y,x)) y = 0;
if(x==1){
cout<<"0\n";
continue;
}
now = n-(siz[x]+siz[y]);
weight[0] = weight[1] = tot = 0;
int pos = rt;
while(1){
int u = gt(pos);
if(!u) break;
pos = mp[pos][u];
}
if(tot==2&&weight[0]>weight[1])
swap(weight[0],weight[1]);
for(int i = 0;i<tot;i++)
cout<<weight[i]<<" ";
cout<<"\n";
}
return 0;
}
剩下两种做法不是很熟悉,截个图看看就行
#include<bits/stdc++.h>
#define For(i, a, b) for (int i = (a); i <= (b); ++i)
#define Rof(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
using i64 = long long;
constexpr int _N = 1e5 + 5;
int n, m, len;
vector<int> e[_N];
mt19937 rnd(114514);
#define rand(l, r) uniform_int_distribution<int>(l, r)(rnd)
int siz[_N], id[_N], dep[_N], dfn, fa[_N];
set<pair<int, int>> fmx[_N];
vector<int> cr;
bool isc[_N];
void Dfs(int x, int F) {
siz[x] = 1, id[x] = ++dfn, dep[x] = dep[F] + 1, fa[x] = F;
auto Add = [&x](int s, int siz) {
fmx[x].insert({ siz, s });
if (fmx[x].size() > 3)
fmx[x].erase(fmx[x].begin());
};
for (int v : e[x]) if (v ^ F) {
Dfs(v, x);
siz[x] += siz[v];
Add(v, siz[v]);
}
}
inline bool In(int x, int y) { return id[y] >= id[x] && id[y] < id[x] + siz[x]; }
vector<int> ans;
void Ask(int x, int y) {
ans.clear();
if (dep[x] > dep[y]) swap(x, y);
if (In(x, y)) y = 0;
int p = 1, tot = n - siz[x] - siz[y];
auto GetSiz = [](int x, int dx, int dy) {
if (In(dx, x) || In(dy, x)) return 0;
int sum = siz[x];
if (In(x, dx)) sum -= siz[dx];
if (In(x, dy)) sum -= siz[dy];
return sum;
};
for (int c : cr)
if (GetSiz(c, x, y) > tot / 2 && dep[c] > dep[p])
p = c;
while (tot - GetSiz(p, x, y) <= tot / 2) {
int nxt = 0, mx = 0;
for (auto pr : fmx[p])
if (GetSiz(pr.second, x, y) > mx)
mx = GetSiz(pr.second, x, y), nxt = pr.second;
if (mx <= tot / 2) ans.push_back(p);
p = nxt;
}
sort(ans.begin(), ans.end());
for (int r : ans) cout << r << ' ';
cout << '\n';
}
signed main() {
string file = "dream";
freopen((file + ".in").c_str(), "r", stdin);
freopen((file + ".out").c_str(), "w", stdout);
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
len = max(1, (int)(sqrt(n) * 1.5));
For(i, 1, len) isc[rand(1, n)] = 1;
For(i, 1, n) if (isc[i]) cr.push_back(i);
For(i, 2, n) {
int x, y;
cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}
Dfs(1, 0);
For(i, 1, m) {
int x, y;
cin >> x >> y;
if (x == 1 || y == 1) cout << 0 << '\n';
else Ask(x, y);
}
}
#include<cstdio>
#include<algorithm>
#include<ctime>
using namespace std;
const int inf=0x3f3f3f3f;
struct node{int size,id,iid;};
struct edge{int last,en,next;} e[200010];
int n,x,y,son[100010],size[100010],dfn[100010],dep[100010];
int st[100010][18],tot,cnt,cs[100010],q,u,v,ccs[100010];
int f[100010][18],val[100010],g[100010][18],leave[100010],ans,w,sum;
void add(int x,int y)
{
e[++tot].en=y;
e[tot].next=e[x].last;
e[x].last=tot;
}
inline int read()
{
int s=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s;
}
void dfs(int x,int fa)
{
f[x][0]=fa;dep[x]=dep[fa]+1;size[x]=1;
dfn[x]=++cnt;son[x]=0;
for(int i=e[x].last;i;i=e[i].next)
if (e[i].en!=fa)
{
dfs(e[i].en,x);
if (size[son[x]]<size[e[i].en])
{
ccs[x]=cs[x];
cs[x]=son[x];
son[x]=e[i].en;
}
else if (size[cs[x]]<size[e[i].en])
{
ccs[x]=cs[x];
cs[x]=e[i].en;
}
else if (size[ccs[x]]<size[e[i].en]) ccs[x]=e[i].en;
size[x]+=size[e[i].en];
}
val[x]=size[son[x]]-size[cs[x]];
if (!cs[x]) val[x]=0x3f3f3f3f;
st[x][0]=val[x];g[x][0]=son[x];
leave[x]=++tot;
}
int lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=17;i>=0;i--)
if (dep[f[x][i]]>=dep[y]) x=f[x][i];
if (x==y) return x;
for (int i=17;i>=0;i--)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int calc(int z,int x)
{
if (dfn[u]>=dfn[x]&&leave[u]<=leave[x]) z-=size[u];
if (dfn[v]>=dfn[x]&&leave[v]<=leave[x]) z-=size[v];
return z;
}
bool getpos(int x,int y)
{
if (dfn[x]>=dfn[y]&&leave[x]<=leave[y]) return true;
return false;
}
void sort3(node &a,node &b,node &c)
{
if (a.size<b.size) swap(a,b);
if (a.size<c.size) swap(a,c);
if (b.size<c.size) swap(b,c);
}
void sort3(int &a,int &b,int &c)
{
if (a<b) swap(a,b);
if (a<c) swap(a,c);
if (b<c) swap(b,c);
}
bool get(int x)
{
int a,b,c;
a=calc(size[son[x]],son[x]);
b=calc(size[cs[x]],cs[x]);
c=calc(size[ccs[x]],ccs[x]);
sort3(a,b,c);
if (a<=sum/2) return true;
return false;
}
void getans(int x)
{
for (int i=17;i>=0;i--)
if (f[x][i]&&get(f[x][i])) x=f[x][i];
int y=0;
node a,b,c;
a=(node){calc(size[son[x]],son[x]),getpos(u,son[x])?u:getpos(v,son[x])?v:0,son[x]};
if (son[x]==u||son[x]==v) a.size=-inf;
b=(node){calc(size[cs[x]],cs[x]),getpos(u,cs[x])?u:getpos(v,cs[x])?v:0,cs[x]};
if (son[x]==u||son[x]==v) a.size=-inf;
c=(node){calc(size[ccs[x]],ccs[x]),getpos(u,ccs[x])?u:getpos(v,ccs[x])?v:0,ccs[x]};
if (son[x]==u||son[x]==v) a.size=-inf;
sort3(a,b,c);
if (sum-a.size<=sum/2&&a.size!=-inf) y=a.iid;
if (x>y) swap(x,y);
if (x) printf("%d %d\n",x,y);
else printf("%d\n",y);
}
void solve(int x)
{
bool bj=getpos(w,x);
if (!bj)
{
for (int i=17;i>=0;i--)
if (g[x][i]) x=g[x][i];
getans(x);
return;
}
else
{
for (int i=17;i>=0;i--)
{
int y=g[x][i];
if (!y||!getpos(w,y)&&y!=w||getpos(y,u)||getpos(y,v)) continue;
if (calc(st[x][i],y)>=0) x=y;
}
}
node a,b,c;
if (x==u||x==v) x=f[x][0];
a=(node){calc(size[son[x]],son[x]),getpos(u,son[x])?u:getpos(v,son[x])?v:0,son[x]};
if (son[x]==u||son[x]==v||!son[x]) a.size=-inf;
b=(node){calc(size[cs[x]],cs[x]),getpos(u,cs[x])?u:getpos(v,cs[x])?v:0,cs[x]};
if (cs[x]==u||cs[x]==v||!cs[x]) b.size=-inf;
c=(node){calc(size[ccs[x]],ccs[x]),getpos(u,ccs[x])?u:getpos(v,ccs[x])?v:0,ccs[x]};
if (ccs[x]==u||ccs[x]==v||!ccs[x]) c.size=-inf;
sort3(a,b,c);
if (a.size==-inf)
{
getans(x);
return;
}
if (getpos(a.iid,w)) w=a.id;
solve(a.iid);
}
int main()
{
freopen("dream.in","r",stdin);
freopen("dream.out","w",stdout);
n=read();q=read();
for (int i=1;i<n;i++)
x=read(),y=read(),add(x,y),add(y,x),st[i][0]=inf;
st[0][0]=inf;
dfs(1,0);
for (int j=1;j<=17;j++)
for (int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1],g[i][j]=g[g[i][j-1]][j-1];
st[i][j]=min(st[i][j-1],st[g[i][j-1]][j-1]);
}
dfn[0]=leave[0]=size[0]=0;
while (q--)
{
scanf("%d%d",&u,&v);ans=0;
if (u==1||v==1)
{
printf("0\n");
continue;
}
w=lca(u,v);
if (u==w) v=0;
else if (v==w) u=0;
sum=n-size[u]-size[v];
solve(1);
}
return 0;
}
T4
你在期待什么?
标签:getpos,int,siz,son,231004,校内,size,define From: https://www.cnblogs.com/cztq/p/17743540.html