来中山纪中半个月了,差不多就要结束了,

写一些之前考试能更正的题解吧,还有一些不是给人做的(比如IOI2018互测。。

备注:我不会的就没有放上来了,所有数学有关的基本上都死了。

所以这里的题目都是相对其他考的而言简单的题qwq,然而我考场上还是不会做

写完之后发现只会分块和线段树qwq,偶尔有点网络流,其他都不会,awsl

3.18

第一天来就考NOI NO.2的题目。。

题目看这里吧

more?more!

这道题非常奇妙的地方在于

因为\(n\)是固定的所以\(n+1\)本就是不需要求的状态,

然后对于\(O(n^2)\)就是\(f_{n+1,i}=f_{n,i}*p^i+f_{n,i-1}*(1-p)^{n-i+1}\)

利用\(f_{n+1,i}\)是可以从两个方程中转移过来的,我们就可以得出有效状态\(f_{n,i}\)了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
const ll N=1e6+6;
const ll mod=998244353;
ll n,p,inv[N],finv[N],f[N];
ll read(){
ll x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
} void init(){
inv[1]=1;finv[1]=1;f[1]=1;
for(ll i=2;i<=n;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(ll i=2;i<=n;i++)finv[i]=finv[i-1]*inv[i]%mod;
for(ll i=2;i<=n;i++)f[i]=f[i-1]*i%mod;
} ll ksm(ll x,ll k){
ll ans=1;
while(k){
if(k&1)ans=(ans*x)%mod;x=(x*x)%mod;k>>=1;
}return ans%mod;
} int main(){
freopen("more.in","r",stdin);
freopen("more.out","w",stdout);
n=read();p=read();init();
if(p==499122177){
for(ll i=1;i<n;i++){
ll sum=((finv[n-i]*finv[i])%mod)*f[n]%mod;
sum=(sum%mod*ksm(ksm(p,n-i)%mod,i))%mod;
printf("%lld ",sum);
}
}
else {
ll sum=1,tmp;
for(ll i=1;i<n;i++){
tmp=ksm(((ksm(p,i)-ksm((1-p+mod)%mod,i)+mod)%mod),mod-2)%mod;
sum=sum*(tmp*((ksm(p,n-i+1)-ksm((1-p+mod)%mod,n-i+1)+mod)%mod)%mod)%mod;
printf("%lld ",sum);
}
}
return 0;
}

3.19

唯一比较容易的一天qwq

题目看这里吧

这里是官方题解

T1

数据结构维护dp

第一题就是要下放很多的线段求满足条件的下方,二位偏序,然后卡线段树。

二位偏序排个序就好了(我不会说我这个没想到qwq)

线段树维护dp最大值->树状数组维护

什么?你说树状数组\(log^2\),因为这里我们的序列是单调的,所以直接下放直接查就可以了,这种树状数组只能在这种情况下用。

别人线段树比我树状数组快系列qwq

哦对了,因为这道题叫fc,然后在Windows下面对拍也是fc,就变成了跑了两次这个代码,并没有比较文件输出。所以它全程没给我跑出错误,搞得我当时以为A了。

#include<bits/stdc++.h>
#define ll long long
#define ls root<<1
#define rs root<<1|1
#define max(a,b) a>b?a:b
using namespace std;
const ll N=1e6+5;
ll vis[21],n,m,ti[N],ai[N],ans,s[21];
ll f[N],id[N];
ll read(){
ll x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
} void work_20(){
for(ll i=0;i<(1<<n);i++){
ll sum=0,flag=0;memset(vis,0,sizeof(vis));
for(ll j=1;j<=n;j++)if((1<<(j-1))&i)vis[j]=1;
for(ll j=1;j<=n;j++)s[j]=s[j-1]+vis[j];
for(ll j=1;j<=n;j++)
if(vis[j]&&((s[min(j+ti[j],n)]-s[j-1]>1)||(s[j]-s[max(0ll,j-ti[j]-1)]>1)))flag=1;
if(flag)continue;
for(ll j=1;j<=n;j++)if(vis[j])sum+=ai[j];
ans=max(sum,ans);
}
cout<<ans<<endl;
} void work_15(){
ll ans=0;
for(ll i=1;i<=n;i++)f[i]=ai[i];
for(ll i=1;i<=n;i++)
for(ll j=0;j<i;j++){
if(i-ti[i]<=j||ti[j]+j>=i)continue;
f[i]=max(f[i],f[j]+ai[i]);
}
for(int i=1;i<=n;i++)ans=max(ans,f[i]);
cout<<ans<<endl;
} ll mx[N<<2],mx2[N<<2],lazy[N<<2]; void update(int root,int left,int right,int v){
if(left==right){mx[root]=f[left];return ;}
int mid=(left+right)>>1;
if(mid>=v) update(ls,left,mid,v);
if(mid<v) update(rs,mid+1,right,v);
mx[root]=max(mx[ls],mx[rs]);
} ll query(int root,int left,int right,int l,int r){
if(left>r||right<l)return -99999999;
if(left>=l&&right<=r)return mx[root];
ll a=-99999999,b=-99999999,mid=(left+right)>>1;
if(mid>=l) a=query(ls,left,mid,l,r);
if(mid<r) b=query(rs,mid+1,right,l,r);
return max(a,b);
} bool cmp(int a,int b){
return a+ti[a]<b+ti[b];
} ll c[N]; void add(ll x){
for(ll i=x;i<=n;i+=(i&(-i)))c[i]=max(c[i],f[x]);
} ll ask(ll x){
ll ans=0;for(ll i=x;i>=1;i-=(i&(-i)))ans=max(c[i],ans);return ans;
} int main(){
freopen("fc.in","r",stdin);
freopen("fc.out","w",stdout);
n=read();ll flag=1;
for(int i=1;i<=n;i++){ti[i]=read();if(ti[i]!=ti[1])flag=0;}
for(int i=1;i<=n;i++)ai[i]=read()*ti[i];
for(int i=1;i<=n;i++)ti[i]--,id[i]=i;
if(n<=20){work_20();return 0;}
if(n<=5000){work_15();return 0;}
for(ll i=1;i<=n;i++)f[i]=ai[i];
if(flag){
for(ll i=1;i<=n;i++){
if(i-ti[i]-1>=1)
f[i]=query(1,1,n,1,i-ti[i]-1)+ai[i];
update(1,1,n,i);
}
}else {
sort(id+1,id+n+1,cmp);int now=1;
for(int i=1;i<=n;i++){
while(id[now]+ti[id[now]]<i&&now<=n)add(id[now]),now++;
if(i-ti[i]-1>=1)f[i]=ask(i-ti[i]-1)+ai[i];
}
}
for(int i=1;i<=n;i++)ans=max(ans,f[i]);
printf("%lld\n",ans);
return 0;
}

T2

就是因为这个东西,本来我已经放弃学SAM了的qwq。

是关于SAM的模板题吧qwq

就是考关于SAM的拼接。因为每个序列只能贡献连续的一段,所以我们从n到1把每个字符串的SAM连接起来。就是建的时候记录一下左右端点。然后拼起来,具体看代码吧。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=4e6+5;
const int mod=1e9+7;
int f[N],n,a[N],tot,last,tmp[5],rt,ls[N],rs[N];
char s[N],ss[N],b[N];
struct node{
int ch[7],len,ff;
}t[N];
int dfs(int x){
if(f[x]!=-1)return f[x];
f[x]=1;
for(int i=1;i<=4;i++){
f[x]+=dfs(t[x].ch[i]);
f[x]%=mod;
}return f[x];
} void print(int x,int k){
puts(ss);
for(int i=1;i<=4;i++){
if(t[x].ch[i]){
ss[k]=b[i];
print(t[x].ch[i],k+1);
}
}ss[k]=0;
} void update(int x){
int p=last,np=last=++tot;
t[np].len=t[p].len+1;
while(p&&!t[p].ch[x])t[p].ch[x]=np,p=t[p].ff;
if(!p)t[np].ff=rt;
else {
int q=t[p].ch[x];
if(t[q].len==t[p].len+1)t[np].ff=q;
else{
int nq=++tot;t[nq]=t[q];
t[nq].len=t[p].len+1;t[q].ff=t[np].ff=nq;
while(p&&t[p].ch[x]==q){t[p].ch[x]=nq;p=t[p].ff;}
}
}
} int main(){
freopen("copy.in","r",stdin);
freopen("copy.out","w",stdout);
memset(f,-1,sizeof(f));f[0]=0;
a['A']=1;a['C']=2;a['G']=3;a['T']=4;
b[1]='A';b[2]='C';b[3]='G';b[4]='T';
cin>>n;
for(int i=1;i<=n;i++){
ls[i]=last=rt=++tot;
scanf("%s",s+1);int len=strlen(s+1);
for(int i=1;i<=len;i++)update(a[s[i]]);
rs[i]=tot;
}
for(int i=n;i>=1;i--){
for(int j=rs[i];j>=ls[i];j--){
for(int k=1;k<=4;k++){
if(!t[j].ch[k])t[j].ch[k]=tmp[k];
}
}
for(int k=1;k<=4;k++)
tmp[k]=t[ls[i]].ch[k];
}
int k;cin>>k;
if(k)print(1,0);
printf("%d\n",dfs(1));
return 0;
}

T3

卡常有点恶心啊qwq

首先对于子序列我们需要用序列自动机(这并不是一个很高大上的东西)维护,不然你会跑很多的重复子序列

肉眼可见的二分图匹配。但是如果我们把每个字符串的子序列都提出来连边建图不就炸了吗

所以套路就在于我们对于每个字符串只要搞出300个关于它的子序列就可以了。

因为这样就一定可以全部匹配了。

好了目前时间复杂度\(O(n^4)\),二分啊。

反正我的程序被卡了一点点时限,也可能有点错误吧,所以我有一个点是打表的。

然后网络流是一定跑不过的别想了,然后我必须搞出1000个关于它的子序列才可以?

如果有大佬可以看看我错哪里,蒟蒻感激不尽

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<vector>
#include<queue>
using namespace std;
vector<int>q[305][305];
map<string,int>mp,mp2;
const int N=301*301*50+5;
const int inf=1e9;
int n,tot,head[301],s,t,ans,cnt,nex[301][31],idx,a[301],ai[301];
int num=1,dep[N],line[N],Q[100001],vis[100001];
string ss[N],sss;
struct node{
int to,nex,c;
}e[N]; void add(int from,int to){
e[++num].to=to;e[num].nex=head[from];head[from]=num;
} int dfs(int x){
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(vis[v])continue;vis[v]=1;
if(!Q[v]||dfs(Q[v])){Q[v]=x;return 1;}
}return 0;
} int get(){
int ans=0;
for(int i=1;i<=n;i++){for(int i=1;i<=tot;i++)vis[i]=0;ans+=dfs(i);}
return ans;
} int find(){
int l=1,r=n;ans=-1;
while(r>=l){
int mid=(l+r+1)>>1;
num=0;memset(head,0,sizeof(head));for(int i=1;i<=tot;i++)Q[i]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=mid;j++)
for(int k=0;k<q[i][j].size();k++)
add(i,q[i][j][k]);//add(q[i][j][k],i);
}
if(get()==n){
r=mid-1;for(int i=n+1;i<=tot;i++)if(Q[i])line[Q[i]]=i;ans=mid;
}
else l=mid+1;
}
} //void dfs(int id,int now,int x,int y,string S){
// if(cnt>310||now>sss.size())return ;
//// cerr<<id<<' '<<now<<' '<<x<<' '<<y<<' '<<S<<endl;
// if(x>=y){
// if(!mp[S])mp[S]=++tot,ss[tot]=S;
// if(!vis[mp[S]])cnt++,q[id][y].push_back(mp[S]),vis[mp[S]]=1;return ;
// }dfs(id,now+1,x+1,y,S+sss[now]);dfs(id,now+1,x,y,S);
//} void init(){
int n=sss.size();
for(int i=n;i>=1;i--){
for(int j=1;j<=26;j++)
nex[i-1][j]=nex[i][j];
if(i!=n)nex[i-1][sss[i]-'a'+1]=i;
}
} void dfs(int id,int x,int y,int limit,string S){
if(cnt>1000||x>sss.size())return ;
if(y>=limit){
cnt++;
if(!mp[S])mp[S]=++tot,ss[tot]=S;q[id][limit].push_back(mp[S]);
return ;
}
for(int i=1;i<=26;i++)
if(nex[x][i])dfs(id,nex[x][i],y+1,limit,S+(char)(i+'a'-1));
} int main(){
freopen("diff.in","r",stdin);
freopen("diff.out","w",stdout);
ios::sync_with_stdio(false);
cin>>n;tot=n;int flag=0;
for(int i=1;i<=n;i++){
cnt=0;
cin>>sss;int l=sss.size();
if(sss=="hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")flag=1;
if(!flag){
init();string S;S+=sss[0];
for(int j=1;j<=l;j++){
dfs(i,0,1,j,S);dfs(i,0,0,j,"");if(cnt>1000)break;
}
}
if(flag){
ai[i]=sss.size();
while(a[ai[i]])ai[i]--;a[ai[i]]=1;
}
}
if(flag){
cout<<300<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=ai[i];j++)
cout<<'h';
cout<<endl;
}return 0;
}
s=0,t=tot+1,find();
if(ans==-1){cout<<ans<<endl;return 0;}
else cout<<ans<<endl;
for(int i=1;i<=n;i++)cout<<ss[line[i]]<<endl;
return 0;
}

3.20

今天自闭了,没交,盯着电脑看了四个小时。

会改正的只有这一道

网上有题解自己搜吧,据说还是错的。

就是因为区间有包含情况所以不能这么转移。

第二题就是加强版天天爱跑步,给你一颗树,m条路径,问你路径相交的个数,注路径有起点时间和终点时间,不相交于点上也是可以的,gaojiaxuan说还可以加强???

第三题就是较强版八邻桥,八邻桥阵2333,就是变成了m条河道,你要怎么修。

3.22

又是自闭的一天。

题目

第一题构造。没得人写,写的都是随机。

第二题多项式相关,wsl

第三题,考场上算错复杂度了算出来的是\(O(n*logn*\sqrt n)\)

其实是\(O(n*log\sqrt n*\sqrt n)\)

就是对于题目,我每次修改只会多出两个区间来,那么用set维护区间,对于每个区间直接\((log^2)\)改,因为均摊下来最多\((n+q)\)个区间所以是接近\(O(n*log^2)\)的,主席树维护。

好了说一大堆,其实我根本没用这个方法。还是分块好.jpg

对于分块,直接维护每个块的乘积,然后修改的话打标记,修改时因为每个整块有b满了和没满的,所以维护b满了的一个数组,然后块内二分当前满了的然后快速幂没满的。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e6+5;
const ll mod=1e9+7;
ll l[N],r[N],ans,a[N],b[N],c[N];
ll mul[N],s[N],bl[N],f[N];
ll n,q,tmp,mx[N];
ll read(){
ll x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
} ll ksm(ll x,ll k){
ll ss=1;
while(k){if(k&1)ss=(ss*x)%mod;x=(x*x)%mod;k>>=1;}
return ss%mod;
} void build(){
tmp=sqrt(n);
for(ll i=1;i<=tmp;i++)
l[i]=(i-1)*tmp+1,r[i]=tmp*i;
if(r[tmp]<n)tmp++;
l[tmp]=r[tmp-1]+1,r[tmp]=n;
for(ll i=1;i<=tmp;i++){
for(ll j=l[i];j<=r[i];j++)
mx[i]=max(mx[i],a[j]),bl[j]=i,c[j]=b[j];sort(c+l[i],c+r[i]+1);
for(ll j=l[i];j<=r[i];j++)
{mul[j]=c[j];if(j>l[i])mul[j]=(mul[j]*mul[j-1])%mod;}
ll sum=1;
for(ll j=l[i];j<=r[i];j++)
sum=(sum*min(b[j],a[j]))%mod;s[i]=sum;
}
} void change(ll x,ll y){
b[x]=y;s[bl[x]]=1;
for(ll i=l[bl[x]];i<=r[bl[x]];i++)c[i]=b[i];
sort(c+l[bl[x]],c+r[bl[x]]+1);
for(ll i=l[bl[x]];i<=r[bl[x]];i++)
{mul[i]=c[i];if(i>l[bl[x]])mul[i]=(mul[i]*mul[i-1])%mod;}
if(f[bl[x]]){for(ll i=l[bl[x]];i<=r[bl[x]];i++)s[bl[x]]=(s[bl[x]]*min(f[bl[x]],b[i]))%mod;}
else for(ll i=l[bl[x]];i<=r[bl[x]];i++)s[bl[x]]=(s[bl[x]]*min(a[i],b[i]))%mod;
} ll add(ll x,ll y){
f[x]=mx[x]=y;s[x]=1;
ll u=lower_bound(c+l[x],c+r[x]+1,y)-c-1;
if(u+1<=r[x])s[x]=(ksm(y,r[x]-u))%mod;
if(u>r[x])u=r[x];
if(u>=l[x])s[x]=(s[x]*mul[u])%mod;
} int main(){
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
n=read();q=read();
for(ll i=1;i<=n;i++)a[i]=read();
for(ll i=1;i<=n;i++)a[i]=max(a[i],a[i-1]);
for(ll i=1;i<=n;i++)b[i]=read();
build();
for(ll i=1;i<=q;i++){
ll opt=read();ans=1;
if(opt==0){
ll x=read(),y=read(),ss=0;
if(f[bl[x]])for(ll i=l[bl[x]];i<=r[bl[x]];i++)a[i]=max(a[i],f[bl[x]]);f[bl[x]]=0;
for(ll i=x;i<=r[bl[x]];i++)a[i]=max(a[i],y),mx[bl[x]]=max(a[i],mx[bl[x]]);
s[bl[x]]=1;for(ll i=l[bl[x]];i<=r[bl[x]];i++)s[bl[x]]=(s[bl[x]]*min(a[i],b[i]))%mod;
ll j=bl[x]+1;
while(mx[j]<y&&j<=tmp)add(j,y),j++;
if(j<=tmp){
for(ll k=l[j];k<=r[j];k++)a[k]=max(a[k],max(f[j],y));
s[j]=1;for(ll k=l[j];k<=r[j];k++)s[j]=(s[j]*min(a[k],b[k]))%mod;
}
for(ll j=1;j<=tmp;j++)ans=(ans*s[j])%mod;
printf("%lld\n",ans%mod);
}else {
ll x=read(),y=read();change(x,y);
for(ll j=1;j<=tmp;j++)ans=(ans*s[j])%mod;
printf("%lld\n",ans%mod);
}
}
return 0;
}

3.23

考了CJ他们的题目

本来就是因为CJ不收去的JZ。然后我在JZ考CJ。ZYYS

第一题。。。分类讨论后没打了,自我感觉和毒瘤很像

第二题。。。神仙组合不过被gaojiaxuan用了一个套路然后好像是可以多项式做出来,据会多项式的人说特别简单比题解良心多了。

只会网络流

考虑最小割。

S连体力流量为1,T连智力流量为1,然后把天数拆点,拆点之间连边流量为1。

然后按题目要求把天数和任务连inf边。

就是说要么这天必须选,要么就是这天要做的任务之前已经被做完了。

一个让人误认为是跑最大答案的网络流。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e5+5;
const int inf=1e9;
int num=1,head[N],k;
int vis[N],dep[N],ti[N],n,m,s,t;
struct node{
int to,nex,c;
}e[N<<1];
int read(){
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
} void add(int from,int to,int c){
e[++num].to=to;e[num].c=c;e[num].nex=head[from];head[from]=num;
} bool bfs(){
memset(dep,0,sizeof(dep));dep[s]=1;
queue<int>q;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(!dep[v]&&e[i].c)q.push(v),dep[v]=dep[u]+1;
}
}return dep[t];
} int dfs(int x,int cap){
if(x==t)return cap;
int addx=0;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;
if(dep[v]==dep[x]+1&&e[i].c){
int tmp=dfs(v,min(e[i].c,cap-addx));
e[i].c-=tmp;e[i^1].c+=tmp;addx+=tmp;
}
}return addx;
} int dinic(){
int ans=0;while(bfs())ans+=dfs(s,inf);return ans;
} int main(){
freopen("deadline.in","r",stdin);
freopen("deadline.out","w",stdout);
n=read();m=read();k=read();s=0;t=m+m+n+1;
for(int i=1;i<=m;i++)add(i,i+m,1),add(i+m,i,0);
for(int i=1;i<=n;i++){
ti[i]=read();
if(ti[i])add(i+m+m,t,1),add(t,i+m+m,0);
else add(s,i+m+m,1),add(i+m+m,s,0);
}
for(int i=1;i<=k;i++){
int x=read(),y=read();
if(!ti[x]) add(x+m+m,y,inf),add(y,x+m+m,0);
else add(y+m,x+m+m,inf),add(x+m+m,y+m,0);
}
printf("%d\n",dinic());
return 0;
}

3.25

没有更正题目。想知道题目问问租酥雨大佬他出的省选联考吧。

反正数学那么多我是自闭了。

3.26

题目

样例

好像是最大子权闭合图的模板题吧。

对于维护两颗不同的树共同连通块,我们考虑对于每一个根跑一次网络流,把它按照题目描述建边,也就是把两颗树的边放到一棵树里面,注意在网络流里的意思是,学了它,它往上的父亲也都被学了,这样就可以维护连通块了。

又不知道为什么,我建图的树边不能重复。也就是两点之间只能有一条inf边。但是fish和jeff的可以???

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int N=2e3+5;
const int inf=1e7;
int n,s,t,num,head[N],dep[N],ch[101][101];
int ans=0,sum=0,a[N],cnt=0;
struct edge{
int to,nex,c;
}e[N*100];
int read(){
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
void add(int from,int to,int c){
num++;e[num].to=to;e[num].c=c;e[num].nex=head[from];head[from]=num;
}
struct node{
int num=0,head[N];
edge e[N*100];
void clean(){memset(head,0,sizeof(head));num=0;}
void add(int from,int to){
num++;e[num].to=to;e[num].nex=head[from];head[from]=num;
}
}A,B;
void dfs1(int x,int ff){
for(int i=A.head[x];i;i=A.e[i].nex){
int v=A.e[i].to;if(v==ff)continue;
if(!ch[v][x])add(v,x,inf),add(x,v,0),ch[v][x]=1;dfs1(v,x);
}
}
void dfs2(int x,int ff){
for(int i=B.head[x];i;i=B.e[i].nex){
int v=B.e[i].to;if(v==ff)continue;
if(!ch[v][x])add(v,x,inf),add(x,v,0),ch[v][x]=1;dfs2(v,x);
}
}
bool bfs(){
memset(dep,0,sizeof(dep));dep[s]=1;int tot=0;
queue<int>q;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(!dep[v]&&e[i].c)dep[v]=dep[u]+1,q.push(v);
}
}return dep[t];
} int dfs(int x,int cap){
if(x==t)return cap;
int addx=0;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;cnt++;
if(dep[v]==dep[x]+1&&e[i].c){
int tmp=dfs(v,min(cap-addx,e[i].c));
e[i].c-=tmp;e[i^1].c+=tmp;addx+=tmp;
}
}return addx;
} int dinic(){
int ans=0;while(bfs())cnt=0,ans+=dfs(s,inf);return ans;
} void solve(){
n=read();ans=inf;sum=0;s=0;t=n+1;
A.clean();B.clean();
int ff=1;
for(int i=1;i<=n;i++)a[i]=read(),sum+=a[i]>0?a[i]:0;
for(int i=1;i<n;i++){
int x=read(),y=read();
A.add(x,y);A.add(y,x);
}
for(int i=1;i<n;i++){
int x=read(),y=read();
B.add(x,y);B.add(y,x);
}
for(int i=1;i<=n;i++){
memset(ch,0,sizeof(ch));
memset(head,0,sizeof(head));num=1;
for(int j=1;j<=n;j++){
if(a[j]>0)add(s,j,a[j]),add(j,s,0);
else add(j,t,-a[j]),add(t,j,0);
}
dfs1(i,i);dfs2(i,i);
int tmp=dinic();
ans=min(ans,tmp);
}printf("%d\n",sum-ans);
} int main(){
freopen("name.in","r",stdin);
freopen("name.out","w",stdout);
int T=read();
while(T--)solve();
return 0;
}

3.27

事先说明这道题不卡\(log^3\)

题目

题解

题解应该已经很清楚了吧qwq

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cmath>
#include<queue>
#define ls root<<1
#define rs root<<1|1
using namespace std;
const int N=5e5+5;
const int inf=1e9;
int lazy[N<<2],s[N<<2];
int n,m,num,head[N],wi[N],dep[N];
int size[N],fa[N],st[N][21],ed[N][21];
int visd[N],visb[N],idd[N],idb[N],bfsid,dfsid;
struct edge{
int to,nex;
}e[N<<1];
int read(){
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
} void add(int from,int to){
num++;e[++num].to=to;e[num].nex=head[from];head[from]=num;
} struct node{
int c[N];
void add(int x){for(int i=x;i<=n;i+=(i&(-i)))c[i]+=1;}
int query(int x){int ans=0;for(int i=x;i;i-=(i&(-i)))ans+=c[i];return ans;}
}T; void dfs(int x){
idd[x]=++dfsid;visd[dfsid]=x;size[x]=1;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(dep[v])continue;
dep[v]=dep[x]+1;fa[v]=x;dfs(v);size[x]+=size[v];
}
} void bfs(){
queue<int>q;q.push(1);
while(!q.empty()){
int x=q.front();q.pop();idb[x]=++bfsid;visb[bfsid]=x;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(v==fa[x])continue;q.push(v);
}
}
} void init(int x){
int left=0,right=0;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(v==fa[x])continue;init(v);
}st[x][0]=idb[x];ed[x][0]=idb[x];
for(int i=1;i<=20;i++){
left=right=0;
for(int j=head[x];j;j=e[j].nex){
int v=e[j].to;if(v==fa[x]||!st[v][i-1])continue;
if(!left)left=v;right=v;
}
st[x][i]=st[left][i-1];ed[x][i]=ed[right][i-1];
if(st[x][i]>ed[x][i])swap(st[x][i],ed[x][i]);
}
} void build(int root,int l,int r){
if(l==r){
s[root]=wi[visb[l]];return ;
}int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
s[root]=min(s[ls],s[rs]);
} void push(int root,int left,int right){
int mid=(left+right)>>1;
lazy[ls]+=lazy[root];lazy[rs]+=lazy[root];
s[ls]+=lazy[root];s[rs]+=lazy[root];
lazy[root]=0;return ;
} void update(int root,int left,int right,int l,int r,int v){
if(left>=l&&right<=r){s[root]-=v;lazy[root]-=v;return ;}
if(lazy[root])push(root,left,right);
int mid=(left+right)>>1;
if(mid>=l) update(ls,left,mid,l,r,v);
if(mid<r) update(rs,mid+1,right,l,r,v);
s[root]=min(s[ls],s[rs]);
} void update2(int root,int left,int right,int k){
if(left==right){s[root]=inf;return ;}
if(lazy[root])push(root,left,right);
int mid=(left+right)>>1;
if(mid>=k) update2(ls,left,mid,k);
if(mid<k) update2(rs,mid+1,right,k);
s[root]=min(s[ls],s[rs]);
} int query(int root,int left,int right,int k){
int mid=(left+right)>>1;
if(left==right){return left;}
if(lazy[root])push(root,left,right);
if(s[ls]==k) return query(ls,left,mid,k);
else return query(rs,mid+1,right,k);
} int ask(int root,int left,int right,int k){
int mid=(left+right)>>1;
if(left==right){return s[root];}
if(lazy[root])push(root,left,right);
if(mid>=k) return ask(ls,left,mid,k);
else return ask(rs,mid+1,right,k);
} int main(){
freopen("pang.in","r",stdin);
freopen("pang.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)wi[i]=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
add(x,y);add(y,x);
}dep[1]=1;dfs(1);bfs();init(1);
build(1,1,n);
m=read();
for(int i=1;i<=m;i++){
int opt=read();
if(opt==1){
int x=read(),y=read(),d=0;
for(int i=0;i<=15;i++){if(st[x][i])update(1,1,n,st[x][i],ed[x][i],(int)(y/pow(2,i)));}
while(fa[x]&&(int)(y/pow(2,d))){
d++;
for(int i=1;i<=15;i++)
if(st[fa[x]][i]&&st[x][i-1]){update(1,1,n,st[x][i-1],ed[x][i-1],-(int)(y/pow(2,i+d)));}
x=fa[x];
for(int i=0;i<=15;i++)
if(st[x][i]){update(1,1,n,st[x][i],ed[x][i],(int)(y/pow(2,i+d)));}
}
while(s[1]<=0){int tmp;T.add(idd[visb[tmp=query(1,1,n,s[1])]]);update2(1,1,n,tmp);}
}else{
int x=read();
printf("%d\n",T.query(idd[x]+size[x]-1)-T.query(idd[x]-1));
}
}
return 0;
}

后记

还有两天就要回来啦,省选退役预定了。

中山纪念中学培训杂题(难的都不在这里面qwq)的更多相关文章

  1. 中山纪念中学培训DAY1

    哇啊啊啊啊啊啊$……$ 并不像说环境怎么样. $Day1$模拟赛 稳重一点选了提高$B$ 然后$5min$后: $t1$装压$DP$最短路 $t2$裸地贪心 $t3……$哇$t3$怎么做啊啊啊啊. $ ...

  2. [小结] 中山纪念中学2018暑期训练小结(划掉)(颓废记)-Day10

    [小结] 中山纪念中学2018暑期训练小结(划掉)(颓废记)-Day10 各位看众朋友们,你们好,今天是2018年08月14日,星期二,农历七月初四,欢迎阅看今天的颓废联编节目 最近发生的灵异事件有 ...

  3. 2019中山纪念中学夏令营-Day21[JZOJ]

    2019中山纪念中学夏令营-Day21[JZOJ] 提高组(B组模拟赛)Team_B (由于本人太弱,并没有订正完题目) (题解大部分是从官方题解文件上摘来的) 日常膜拜大神:じやゆん蒟蒻 正文部分: ...

  4. 2019中山纪念中学夏令营-Day14 图论初步【dijkstra算法求最短路】

    Dijkstra是我学会的第一个最短路算法,为什么不先去学SPFA呢?因为我在luogu上翻到了一张比较神奇的图: 关于SPFA -它死了 以及网上还有各位大佬的经验告诉我:SPFA这玩意很容易被卡. ...

  5. 2019中山纪念中学夏令营-Day20[JZOJ] T1旅游详解

    2019中山纪念中学夏令营-Day20[JZOJ] 提高组B组 Team_B组 T1 旅游 Time Limits: 2000 ms  Memory Limits: 262144 KB Descrip ...

  6. 2019中山纪念中学夏令营-Day4[JZOJ]

    Begin (题目的排序方式:难易程度) 什么是对拍: 对拍是一种在写完程序后,验证自己程序是不是正解的比较方便的方法. 实现过程: 对同一道题,再打一个暴力程序,然后用一些大数据等跑暴力程序来进行验 ...

  7. 2019中山纪念中学夏令营-Day1[JZOJ]

    T1 题目描述: 1999. Wexley接苹果(apple) (File IO): input:apple.in output:apple.out 时间限制: 1000 ms  空间限制: 1280 ...

  8. 2019中山纪念中学夏令营-Day9[JZOJ](第六次模拟赛)

    Begin (题目的排序方式:Unkown其实是按心情排的) 异或:(摘自百度百科) 异或(xor)是一个数学运算符.它应用于逻辑运算.异或的数学符号为“⊕”,计算机符号为“xor”.其运算法则为: ...

  9. 2019中山纪念中学夏令营-Day12[JZOJ]

    Begin (题目的排序方式:题号) 每期新姿势:(今天推荐一位巨佬)Cefola-Kiroxs 推荐知识:namespace的用法(本赛我的代码中将用到) 2019.08.12[NOIP普及组]模拟 ...

随机推荐

  1. The Basics of Numpy

    在python语言中,Tensorflow中的tensor返回的是numpy ndarray对象. Numpy的主要对象是齐次多维数组,即一个元素表(通常是数字),所有的元素具有相同类型,可以通过有序 ...

  2. java web项目发生异常依然能运行

    由于JavaWeb应用业务逻辑的复杂性,容易发生一些意想不到的错误和异常,给系统的调试带来不必要的麻烦,不友好的提示信息使编程者对错误和异常无从下手.特别是当发生异常时,Java异常栈输出的信息只能给 ...

  3. Windows 8.1内置微软五笔输入法

    微软五笔输入法採用86版编码,不是Windows 8.1系统的中文语言的缺省输入法,你在使用它之前须要把它加入到系统输入法中. 在控制面板双击"",然后加入微软五笔输入法. wat ...

  4. cocos2d 3.3 lua 代码加密 luac

    1.0 cocos luacompile 使用方法 我用的普通的cocos2d lua,没用quick,quick好像能够对整个资源包含图像和音频都加密,打包成zip.我看了下luacompile 的 ...

  5. SharePoint 创建网站地图树视图及格式枚举截图

    SharePoint 创建网站地图树视图及格式枚举截图         SharePoint首页隐藏掉左側导航以后,假设要以树视图呈现站点地图也非常easy.         仅仅须要复制v4.mas ...

  6. Unable to access the IIS metabase

    https://stackoverflow.com/questions/12859891/error-unable-to-access-the-iis-metabase 解决方法1 On Window ...

  7. iodine免费上网——本质就是利用dns tunnel建立tcp,然后tcp proxy来实现通过访问虚拟dns0网卡来访问你的dns 授权server

    我的命令: server端: sudo iodined -P passwd -f -DD 10.0.0.100 abc.com client端(直连模式,-r表示使用xxx.abc.com的xxx来转 ...

  8. nginx报错日志:see security.limit_extensions

    访问出现部分.js.css等部分文件被拒绝错误日志如下: 19:20:13 [error] 1181#0: *287 FastCGI sent in stderr: "Access to t ...

  9. 广播Intent的三种方式总结

    1.android有序广播和无序广播的区别 BroadcastReceiver所对应的广播分两类:普通广播和有序广播. 普通广播通过Context.sendBroadcast()方法来发送.它是完全异 ...

  10. Java Servlet 配置

    图片太大,可以右键另存再查看,也可以鼠标点击拖置一下,用浏览器单独承载放大查看.