[HEOI2016/TJOI2016]树
写了个树剖。。。,记一下链头
跑得比暴力还慢,这数据也是太弱了。。。。。。
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#define ll long long
const int M=210000,mod=(int)1e9+7;
int nex[M],head[M],to[M],dep[M],size[M],son[M],id[M],cnt,tot,f[M],flag[M],fl[M],top[M],n,m;
void add(int x,int y){nex[++tot]=head[x];to[tot]=y;head[x]=tot;}
void dfs1(int x){size[x]=1;
for(int i=head[x],tmp;i;i=nex[i]){
if(dep[tmp=to[i]]) continue;
dep[tmp]=dep[x]+1;f[tmp]=x;dfs1(tmp);
size[x]+=size[tmp];son[x]=(size[tmp]>size[son[x]])?tmp:son[x];
}
}
void dfs2(int x,int fa){
id[x]=++cnt;top[x]=fa;
if(!son[x]) return;
dfs2(son[x],fa);
for(int i=head[x];i;i=nex[i])
if(!id[to[i]]) dfs2(to[i],to[i]);
}
int query(int x){
while(!flag[top[x]]) x=f[top[x]];
while(!fl[x])x=f[x];return x;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
flag[1]=fl[1]=1,dep[1]=1,dfs1(1),dfs2(1,1);
while(m--){char s[2];int x;scanf("%s%d",s,&x);
if(s[0]=='C') fl[x]=1,flag[top[x]]=1;
else printf("%d\n",query(x));
}
}
若果没有限制,答案就是(sum(1~n))^m
但有的不能取,直接去掉就可以了。。。因为积得和合并一下同类项就是和的积
[HAOI2012]容易题
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#define ll long long
const int M=2100000,mod=(int)1e9+7;
int sum[M],n,m,k,cnt;
struct node{int x,y;}a[M];
bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
int pow(int a,int k){int ans=1;for(;k;a=(1ll*a*a)%mod,k>>=1) if(k&1) ans=(1ll*ans*a)%mod;return ans;}
int main(){
scanf("%d%d%d",&n,&m,&k);int tmp=(1ll*n*(n+1)>>1)%mod;
for(int i=1;i<=k;i++) scanf("%d%d",&a[i].x,&a[i].y);
std::sort(a+1,a+k+1,cmp);
for(int i=1;i<=k;i++){
if(a[i].x==a[i-1].x&&a[i].y!=a[i-1].y) sum[cnt]=(sum[cnt]-a[i].y)%mod;
else if(a[i].x!=a[i-1].x) sum[++cnt]=(tmp-a[i].y)%mod;
}
int ans=pow(tmp,m-cnt);
for(int i=1;i<=cnt;i++) ans=(1ll*ans*(sum[i]+mod)%mod)%mod;
printf("%d ",ans);
}
[HEOI2015]公约数数列
直接暴力分块
维护一个前缀gcd和亦或和。。
因为前缀gcd是递减的,且大佬说gcd不变的情况多,所以gcd改变直接暴力
不变二分。。。
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define ll long long
#define maxn 100010
using namespace std;
struct node {
ll x;int id;
}b[maxn];
ll Gcd[maxn],Xor[maxn],a[maxn];
int n,m,block,tot,L[1010],q,R[1010],t[maxn];char s[10];
bool cmp(node x,node y) {
return x.x<y.x||(x.x==y.x&&x.id<y.id);
}
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
int lower(ll x,int l,int r){
while(l<=r){
int mid=l+r>>1;
if(b[mid].x>=x) r=mid-1;
else l=mid+1;
}
return r+1;
}
void modify(int x){
Gcd[L[x]]=Xor[L[x]]=a[L[x]];b[L[x]].x=a[L[x]];b[L[x]].id=L[x];
for(int i=L[x]+1;i<=R[x];i++) Gcd[i]=gcd(Gcd[i-1],a[i]),Xor[i]=Xor[i-1]^a[i],b[i].x=Xor[i],b[i].id=i;
sort(b+L[x],b+R[x]+1,cmp);
}
int query(ll x){
ll GCD=a[0],XOR=0;
for(int i=1;i<=tot;i++){
if(GCD==gcd(GCD,Gcd[R[i]])){
if(x%GCD==0){
int tmp=lower((x/GCD)^XOR,L[i],R[i]);
if(((b[tmp].x^XOR)*GCD)==x) return b[tmp].id;
}
XOR^=Xor[R[i]];
}
else {
for(int j=L[i];j<=R[i];j++){
GCD=gcd(GCD,a[j]);XOR^=a[j];
if((GCD*XOR)==x) return j;
}
}
}
return n;
}
int main() {
scanf("%d",&n);
block=sqrt(n);tot=(n-1)/block+1; L[1]=0;
for (int i=0;i<n;i++) {
t[i]=i/block+1;
if (!L[t[i]]&&t[i]!=1) L[t[i]]=i;
R[t[i]]=i;
}
for (int i=0;i<n;i++) scanf("%lld",&a[i]);
for (int i=1;i<=tot;i++) modify(i);
scanf("%d",&q);
for(;q--;){char s[20];ll x,y;
scanf("%s%lld",s,&x);
if(s[0]=='M') scanf("%lld",&y),a[x]=y,modify(t[x]);
else {int ans=0;if((ans=query(x))<n)
printf("%d\n",ans);
else printf("no\n");
}
}
}
[国家集训队]部落战争
这个题竟是网络流。
好像最大流就是非头结点
总结点减去非头结点就行了。。。
我也不知道为什么。。
// luogu-judger-enable-o2
#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int M=210000;int n,m,ss,tt,inf=0x7ffffff,dg[M],r,c,A[4],B[4],id[400][400][2];char a[419][400];
struct danicliu{
int nex[M],cos[M],to[M],head[M],tot,dep[M],cur[M];
queue<int>q;
void init(){
tot=1;memset(head,0,sizeof head);
}
void add(int x,int y,int z){
cos[++tot]=z;
to[tot]=y;
nex[tot]=head[x];
head[x]=tot;
cos[++tot]=0;
to[tot]=x;
nex[tot]=head[y];
head[y]=tot;
}
int bfs(int s,int t){
memset(dep,0,sizeof dep);
dep[s]=1;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x],tmp;i;i=nex[i])
if(!dep[tmp=to[i]]&&cos[i]) dep[tmp]=dep[x]+1,q.push(tmp);
}
return dep[t];
}
int dfs(int x,int t,int w){
if(x==t)return w;
for(int &i=cur[x],tmp,d;i>=2;i=nex[i]){
if(dep[x]==dep[tmp=to[i]]-1&&cos[i]&&(d=dfs(tmp,t,min(w,cos[i])))){
cos[i]-=d;cos[i^1]+=d;
return d;
}
}
return 0;
}
int danic(int s,int t){
int flow=0,f;
while(bfs(s,t)){
while(1){
for(int i=ss;i<=tt;i++) cur[i]=head[i];
flow=flow+(f=dfs(s,t,inf));
if(!f) break;
}
}
return flow;
}
}da;int cnt;
int main(){
scanf("%d%d%d%d",&n,&m,&r,&c);int sum=0;ss=0,tt=2*n*m+10;da.init();
A[1]=A[0]=r,A[2]=A[3]=c,B[1]=-c,B[0]=c,B[2]=r,B[3]=-r;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cin>>a[i][j],id[i][j][0]=++cnt,id[i][j][1]=++cnt;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(a[i][j]=='.') {sum++;
da.add(ss,id[i][j][0],1),da.add(id[i][j][1],tt,1);
for(int k=0;k<4;k++){
int ll=i+A[k],cc=j+B[k];
if(ll<1||cc<1||ll>n||cc>m||a[ll][cc]=='x')continue;
da.add(id[i][j][0],id[ll][cc][1],1);
}
}
}
printf("%d",sum-da.danic(ss,tt));
return 0;
}
[ZJOI2009]狼和羊的故事
求最小割,把狼和羊分成两部分用的最小栅栏,就是最小割,跑最大流
// luogu-judger-enable-o2
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int M=210000;int n,m,ss,tt,inf=0x7ffffff,dg[M],r[M],A[4]={0,0,-1,1},B[4]={-1,1},a[419][400],id[400][400];
struct danicliu{
int nex[M],cos[M],to[M],head[M],tot,dep[M],cur[M];
queue<int>q;
void init(){
tot=1;memset(head,0,sizeof head);
}
void add(int x,int y,int z){
cos[++tot]=z;
to[tot]=y;
nex[tot]=head[x];
head[x]=tot;
cos[++tot]=0;
to[tot]=x;
nex[tot]=head[y];
head[y]=tot;
}
int bfs(int s,int t){
memset(dep,0,sizeof dep);
dep[s]=1;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x],tmp;i;i=nex[i])
if(!dep[tmp=to[i]]&&cos[i]) dep[tmp]=dep[x]+1,q.push(tmp);
}
return dep[t];
}
int dfs(int x,int t,int w){
if(x==t)return w;
for(int &i=cur[x],tmp,d;i>=2;i=nex[i]){
if(dep[x]==dep[tmp=to[i]]-1&&cos[i]&&(d=dfs(tmp,t,min(w,cos[i])))){
cos[i]-=d;cos[i^1]+=d;
return d;
}
}
return 0;
}
int danic(int s,int t){
int flow=0,f;
while(bfs(s,t)){
while(1){
for(int i=ss;i<=tt;i++) cur[i]=head[i];
flow=flow+(f=dfs(s,t,inf));
if(!f) break;
}
}
return flow;
}
}da;int cnt;
int main(){
scanf("%d%d",&n,&m);ss=0,tt=n*m+1;da.init();
for(int i=1;i<=n;i++)a[i][0]=-1,a[i][m+1]=-1;
for(int i=1;i<=m;i++)a[0][i]=-1,a[n+1][i]=-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),id[i][j]=++cnt;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(a[i][j]==1)da.add(ss,id[i][j],inf);
if(a[i][j]==2){da.add(id[i][j],tt,inf);continue;}
for(int k=0;k<4;k++){
int ll=i+A[k],cc=j+B[k];
if(a[ll][cc]==-1||a[ll][cc]==1)continue;
da.add(id[i][j],id[ll][cc],1);
}
}
printf("%d",da.danic(ss,tt));
return 0;
}
[AHOI2014/JSOI2014]支线剧情
上下界网络流。。。
不会,好像是建一个超源一个超汇
预先跑满一个为下届的流
再连一个为上届建下届的流
// luogu-judger-enable-o2
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int M=210000;int n,m,ss,tt,inf=0x7fffffff,dg[M],r[M];
struct danicliu{
int nex[M],cos[M],to[M],head[M],tot,vis[M],dis[M],flow[M],cap[M],id[M],pre[M],mflow,mcost;
queue<int>q;
void init(){
tot=1;memset(head,0,sizeof head);mflow=mcost=0;
}
void add(int x,int y,int z,int w){
cos[++tot]=w;
cap[tot]=z;
to[tot]=y;
nex[tot]=head[x];
head[x]=tot;
cos[++tot]=-w;
cap[tot]=0;
to[tot]=x;
nex[tot]=head[y];
head[y]=tot;
}
int bfs(int s,int t){
memset(vis,0,sizeof vis);
memset(pre,-1,sizeof pre);
for(int i=1;i<=tt;i++) dis[i]=inf;
dis[s]=0;q.push(s);vis[s]=1;flow[s]=inf;
while(!q.empty()){
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x],tmp;i>=2;i=nex[i]){
if(dis[tmp=to[i]]>dis[x]+cos[i]&&cap[i]) {
dis[tmp]=dis[x]+cos[i];id[tmp]=i;
pre[tmp]=x;flow[tmp]=min(flow[x],cap[i]);
if(!vis[tmp]) vis[tmp]=1,q.push(tmp);
}
}
}
return dis[t]<inf;
}
void maxflow(int s,int t){
while(bfs(s,t)){
int k=t;
while(k!=s){
cap[id[k]]-=flow[t];
cap[id[k]^1]+=flow[t];
k=pre[k];
}
mflow+=flow[t];
mcost+=flow[t]*dis[t];
}
}
}da;
int main(){
scanf("%d",&n);ss=n+1,tt=n+2;da.init();
for(int i=1,out;i<=n;i++){
scanf("%d",&out);
for(int j=1,v,w;j<=out;j++){
scanf("%d%d",&v,&w);dg[v]+=w;r[v]++;
da.add(i,v,inf,w);
//da.add(ss,v,1,w);
}
da.add(i,tt,out,0);
if(i!=1)da.add(i,1,inf,0);
}for(int i=1;i<=n;i++){
if(dg[i]){
da.add(ss,i,1,dg[i]);
if(r[i]>1) da.add(ss,i,r[i]-1,0);
}
}
da.maxflow(ss,tt);
printf("%d",da.mcost);
return 0;
}
[HEOI2015]兔子与樱花
暴力贪心
把最小儿子给爸爸
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
const int M=2100000;
int n,m,c[M],l[M],r[M],to[M],ans;
bool cmp(int a,int b){return c[a]<c[b];}
void dfs(int x){
for(int i=l[x];i<=r[x];i++) dfs(to[i]);
std::sort(to+l[x],to+r[x]+1,cmp);
for(int i=l[x];i<=r[x];i++)
if(c[to[i]]+c[x]-1<=m) ans++,c[x]+=c[to[i]]-1;
else return ;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1,t,cnt=0;i<=n;i++) {
scanf("%d",&t);l[i]=cnt+1,r[i]=cnt+t;c[i]+=t;cnt=r[i];
for(int j=l[i];j<=r[i];j++) scanf("%d",&to[j]),to[j]++;
}dfs(1);
printf("%d",ans);
}