20160529~20160604 13

蒟蒻Yzm

20160530

bzoj2333 http://www.lydsy.com/JudgeOnline/problem.php?id=2333

题意:

有N个节点,M个操作:连接两个节点、单个节点的权值增加v、节点所在的连通块的所有节点的权值增加v、所有节点的权值增加v、询问节点当前的权值、询问节点所在的连通块中权值最大的节点的权值、询问所有节点中权值最大的节点的权值。

N,M≤300000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <set>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 300100
 7 #define INF 0x3fffffff
 8 using namespace std;
 9
10 int fa[maxn],ch[maxn][2],tg[maxn],v[maxn],n,m,add;
11 multiset <int> st;
12 void pushdown(int x){
13     if(tg[x]){
14         if(ch[x][0])tg[ch[x][0]]+=tg[x],v[ch[x][0]]+=tg[x];
15         if(ch[x][1])tg[ch[x][1]]+=tg[x],v[ch[x][1]]+=tg[x];
16         tg[x]=0;
17     }
18 }
19 int dt[maxn],dts;
20 int find(int x){
21     dt[dts=1]=x; while(fa[x])x=fa[x],dt[++dts]=x;
22     for(int i=dts;i>=1;i--)pushdown(dt[i]); return x;
23 }
24 int merge(int x,int y){
25     if(!x||!y)return x+y; if(v[x]<v[y])swap(x,y); pushdown(x);
26     ch[x][1]=merge(ch[x][1],y); fa[ch[x][1]]=x; swap(ch[x][0],ch[x][1]); return x;
27 }
28 int del(int x){
29     int t=merge(ch[x][0],ch[x][1]),f=fa[x]; fa[x]=ch[x][0]=ch[x][1]=0;
30     fa[t]=f; if(f)ch[f][ch[f][1]==x]=t; return t;
31 }
32 void update1(int x,int val){
33     int y=find(x); int t=del(x); v[x]+=val;
34     if(y!=x){
35         int z=merge(y,x); st.erase(st.find(v[y])); st.insert(v[z]);
36     }else{
37         if(t){
38             int z=merge(t,x); st.erase(st.find(v[x]-val)),st.insert(v[z]);
39         }else st.erase(st.find(v[x]-val)),st.insert(v[x]);
40     }
41 }
42 void update2(int x,int val){
43     x=find(x); tg[x]+=val; v[x]+=val; if(!fa[x])st.erase(st.find(v[x]-val)),st.insert(v[x]);
44 }
45 void update3(int val){add+=val;}
46 int query1(int x){find(x); return v[x];}
47 int query2(int x){int y=find(x); return v[y];}
48 int query3(){return * --st.find(INF);}
49 void connect(int x,int y){
50     int xx=find(x),yy=find(y); if(xx==yy)return; int z=merge(xx,yy);
51     if(z==xx)st.erase(st.find(v[yy]));else st.erase(st.find(v[xx]));
52 }
53 char opt[3];
54 int main(){
55     //freopen("test.txt","r",stdin);
56     scanf("%d",&n); add=0; st.clear();
57     inc(i,1,n){
58         scanf("%d",&v[i]); st.insert(v[i]); fa[i]=ch[i][0]=ch[i][1]=tg[i]=0;
59     }
60     scanf("%d",&m);
61     inc(i,1,m){
62         scanf("%s",opt); int x,y;
63         if(opt[0]==‘U‘)scanf("%d%d",&x,&y),connect(x,y);
64         if(opt[0]==‘A‘){
65             if(opt[1]==‘1‘)scanf("%d%d",&x,&y),update1(x,y);
66             if(opt[1]==‘2‘)scanf("%d%d",&x,&y),update2(x,y);
67             if(opt[1]==‘3‘)scanf("%d",&x),update3(x);
68         }
69         if(opt[0]==‘F‘){
70             if(opt[1]==‘1‘)scanf("%d",&x),printf("%d\n",query1(x)+add);
71             if(opt[1]==‘2‘)scanf("%d",&x),printf("%d\n",query2(x)+add);
72             if(opt[1]==‘3‘)printf("%d\n",query3()+add);
73         }
74         //if(i==2)break;
75     }
76     return 0;
77 }

题解:可并堆,虽然听说配对堆非常快,但教程太少了不会写,所以去学了斜堆,比较好写。斜堆实际上是一棵二叉树,核心是合并操作,这是一个递归过程,有点像treap的删除操作。斜堆保证复杂度的方法是每次递归合并右节点,合并完后交换左右节点,使整棵树和splay一样,可以“自动”平衡,也是玄学。要修改整个连通块,打标记就行了。这道题特殊的一点在于询问所有节点权值的最大值,可以用STL的set维护所有连通块的根节点,当连边和修改权值时如果根节点被修改需要维护一下set。

2、bzoj2039 http://www.lydsy.com/JudgeOnline/problem.php?id=2039

题意:有N个经理,Ei,j表示i经理对j经理的了解程度,当经理i和经理j同时被雇佣时,利润增加Ei,j*2。同时,雇佣每一个经理都需要花费一定的金钱Ai。没有被雇佣的人会被竞争对手所雇佣,使得所赚得的利润减少Ei,j(意思是经理i和j如果只雇佣一个,就会少Ei,j,如果两个都没被雇佣就不扣钱)。求最大利润。N≤1000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define maxn 1100
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define INF 1000000000000000000
 8 #define ll long long
 9 using namespace std;
10
11 struct e{int t;ll c;int n;}; e es[maxn*2000]; int g[maxn],ess;
12 inline void pe(int f,int t,ll c){
13     es[++ess]=(e){t,c,g[f]}; g[f]=ess; es[++ess]=(e){f,0,g[t]}; g[t]=ess;
14 }
15 inline void pe2(int f,int t,ll c){
16     es[++ess]=(e){t,c,g[f]}; g[f]=ess; es[++ess]=(e){f,c,g[t]}; g[t]=ess;
17 }
18 inline void init(){
19     ess=-1; memset(g,-1,sizeof(g));
20 }
21 queue <int> q; int h[maxn];
22 bool bfs(int s,int t){
23     memset(h,-1,sizeof(h)); while(!q.empty())q.pop(); h[s]=0; q.push(s);
24     while(! q.empty()){
25         int x=q.front(); q.pop();
26         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==-1)h[es[i].t]=h[x]+1,q.push(es[i].t);
27     }
28     return h[t]!=-1;
29 }
30 ll dfs(int x,int t,ll f){
31     if(x==t)return f; ll u=0;
32     for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==h[x]+1){
33         ll w=dfs(es[i].t,t,min(f,es[i].c)); f-=w; u+=w; es[i].c-=w; es[i^1].c+=w; if(f==0)return u;
34     }
35     if(u==0)h[x]=-1; return u;
36 }
37 ll dinic(int s,int t){
38     ll f=0; while(bfs(s,t))f+=dfs(s,t,INF); return f;
39 }
40 int n,s,t; ll a[maxn],b,tot;
41 int main(){
42     scanf("%d",&n); s=0; t=n+1; init(); inc(i,1,n)scanf("%lld",&b),pe(s,i,b); memset(a,0,sizeof(a));
43     inc(i,1,n)inc(j,1,n){
44         scanf("%lld",&b); if(i>j||b==0)continue; a[i]+=b; a[j]+=b; pe2(i,j,2*b); tot+=2*b;
45     }
46     inc(i,1,n)pe(i,t,a[i]); printf("%lld",tot-dinic(s,t)); return 0;
47 }

题解:S集表示雇佣,T集表示不雇佣。每个经理拆成x,y两点。s向所有x点连,流量为雇佣费用。对于每个Ei,j,i,j经理连一条流量为2*Ei,j的无向边,同时i和j都向t连流量为Ei,j的边,最小割为所有Ei,j*2减最大流。由于边数大,需要合并一下边。

20160531

3、bzoj1588 http://www.lydsy.com/JudgeOnline/problem.php?id=1588

题意:n天,每天得到一个值,要求输出每一天和这天得到的值相差最小的之前天得到的值与这个值的差的和。n不知道,不过O(nlog2n)可写。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <set>
 5 #define INF 2147483647
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 using namespace std;
 8
 9 int n,ans,x; set <int> st;
10 int main(){
11     scanf("%d",&n); st.clear(); st.insert(INF); st.insert(-INF); ans=0;
12     inc(i,1,n){
13         scanf("%d",&x);
14         if(i==1)ans+=x;else{
15             int y=* (st.lower_bound(x)),z=* (--st.lower_bound(x)); //printf("%d %d\n",y,z);
16             if(y==INF)ans+=abs(x-z);else if(z==-INF)ans+=abs(x-y);else ans+=min(abs(x-z),abs(x-y));
17         }
18         st.insert(x);
19     }
20     printf("%d",ans); return 0;
21 }

题解:说是平衡树模板题,不过可以用set水过去。先在set插入一个-INF和INF防溢出(yyl大爷教我的)每次在set中lower_bound这天得到的值,求出的是≤它的最大值,比较一下这个值和set中这个值的后继与这天得到的值的差。

4、bzoj2809 http://www.lydsy.com/JudgeOnline/problem.php?id=2809

题意:n个点组成一棵树,每个点都有一个领导力和费用,可以让一个点当领导,然后在这个点的子树中选择一些费用之和不超过m的点,得到领导的领导力乘选择的点的个数(领导可不被选择)的利润。求利润最大值。n≤100000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 100100
 6 #define ll long long
 7 using namespace std;
 8
 9 int ch[maxn][2],rt[maxn],n,m,st; ll sz[maxn],v[maxn],ans,sm[maxn],gd[maxn];
10 struct e{int t,n;}; e es[maxn]; int ess,g[maxn];
11 void pe(int f,int t){es[++ess]=(e){t,g[f]}; g[f]=ess;}
12 void init(){ess=0; memset(g,0,sizeof(g));}
13 void update(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; sm[x]=sm[ch[x][0]]+sm[ch[x][1]]+v[x];}
14 int merge(int x,int y){
15     if(!x||!y)return x+y; if(v[x]<v[y])swap(x,y); ch[x][1]=merge(ch[x][1],y);
16     swap(ch[x][0],ch[x][1]); update(x); return x;
17 }
18 void pop(int &x){
19     int y=merge(ch[x][0],ch[x][1]); ch[x][0]=ch[x][1]=0; sz[x]=1; sm[x]=v[x]; x=y;
20 }
21 void dfs(int x){
22     rt[x]=x; for(int i=g[x];i;i=es[i].n)dfs(es[i].t),rt[x]=merge(rt[x],rt[es[i].t]);
23     while(sz[rt[x]]&&sm[rt[x]]>m)pop(rt[x]); ans=max(ans,sz[rt[x]]*gd[x]);
24 }
25 int main(){
26     scanf("%d%d",&n,&m); init();
27     inc(i,1,n){
28         int a; ll b,c; scanf("%d%lld%lld",&a,&b,&c); if(a)pe(a,i);else st=i;
29         v[i]=sm[i]=b; sz[i]=1; gd[i]=c; ch[i][0]=ch[i][1]=rt[i]=0;
30     }
31     ans=0; dfs(st); printf("%lld",ans); return 0;
32 }

题解:可并堆。可以得到一个结论,就是在子树中选点的时候,先选所有点,如果费用超了,就不断把费用最大的剔除,知道费用不超,这样得到的选点数量最大,这过程可以用堆维护。同时每个点的堆都可以由子树的堆合并得到,所以需要可并堆。

5、bzoj1196 http://www.lydsy.com/JudgeOnline/problem.php?id=1196

题意:修n-1条公路将n个点连通,每个点可建一级公路也可建二级公路,要求一级公路必须有k条,要求花费最多的公路花费最少。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 10500
 6 using namespace std;
 7
 8 int n,k,m,u[maxn*2],v[maxn*2],c1[maxn*2],c2[maxn*2],mx,fa[maxn],cnt;
 9 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
10 bool check(int lim){
11     inc(i,1,n)fa[i]=i; cnt=0;
12     inc(i,1,m)if(c1[i]<=lim){
13         int x=find(u[i]),y=find(v[i]); if(x==y)continue; fa[y]=x; cnt++;
14     }
15     if(cnt<k)return 0;
16     inc(i,1,m)if(c2[i]<=lim){
17         int x=find(u[i]),y=find(v[i]); if(x==y)continue; fa[y]=x; cnt++;
18     }
19     if(cnt<n-1)return 0; return 1;
20 }
21 int main(){
22     scanf("%d%d%d",&n,&k,&m); mx=0;
23     inc(i,1,m-1)scanf("%d%d%d%d",&u[i],&v[i],&c1[i],&c2[i]),mx=max(mx,c1[i]),mx=max(mx,c2[i]);
24     int l=0,r=mx,ans;
25     while(l<=r){
26         int mid=(l+r)>>1;
27         if(check(mid))ans=mid,r=mid-1;else l=mid+1;
28     }
29     printf("%d",ans); return 0;
30 }

题解:首先二分,接着判定:先在不产生环的前提下(用并查集维护)让每条路尽量修一级公路,如果最后

20160602

6、bzoj1218 http://www.lydsy.com/JudgeOnline/problem.php?id=1218

题意:坐标系上有n个目标,每个目标有一个价值,现在求一个边与坐标轴平行,边长为R的正方形,使在其内部(原题是不包括边界,然而实际上不是这样)的目标价值最大。所有坐标为0到5000的整数,n≤10000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 5500
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7
 8 int sum[maxn][maxn],n,mxxy,r,mx;
 9 int main(){
10     scanf("%d%d",&n,&r); mxxy=mx=0;
11     inc(i,1,n){
12         int x,y,z; scanf("%d%d%d",&x,&y,&z); x++; y++;
13         mxxy=max(mxxy,x); mxxy=max(mxxy,y); sum[x][y]+=z;
14     }
15     inc(i,1,mxxy)inc(j,1,mxxy)
16         sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
17     inc(i,r,mxxy)inc(j,r,mxxy)
18         mx=max(mx,sum[i][j]-sum[i][j-r]-sum[i-r][j]+sum[i-r][j-r]);
19     printf("%d",mx); return 0;
20 }

题解:预处理一下以横纵坐标为节点的二维前缀和,然后枚举正方形右上角坐标即可。注意可以将坐标系向右上移动一个单位使前缀和不用考虑负数。

反思:蒟蒻好弱啊,枚举时i和j的边界都应该是所以节点横坐标最大值与纵坐标最大值的最大值。蒟蒻一开始没注意到这一点,以为自己预处理写错。改来改去,WA来WA去。最后对着标程一点点改才发现问题。QAQ

7、bzoj1295 http://www.lydsy.com/JudgeOnline/problem.php?id=1295

题意:N*M块地,如果两块地都没有障碍物,则互相可达。如果两块地互相可达(可经过其他地)则它们之间的距离为它们中心点的欧几里得距离,求如果能移走不大于T个障碍物,土地间的最大距离。N,M≤30

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #include <cmath>
 6 #include <cctype>
 7 #define maxn 100
 8 #define inc(i,j,k) for(int i=j;i<=k;i++)
 9 using namespace std;
10
11
12 int map[maxn][maxn],n,m,k; double mx;
13 bool vis[maxn][maxn],inq[maxn][maxn]; int d[maxn][maxn];
14 struct qn{int x,y;}; queue <qn> q;
15 void spfa(int sx,int sy){
16     while(!q.empty())q.pop(); q.push((qn){sx,sy}); memset(d,-1,sizeof(d)); memset(inq,0,sizeof(inq));
17     memset(vis,0,sizeof(vis)); d[sx][sy]=map[sx][sy]; inq[sx][sy]=1;
18     while(!q.empty()){
19         qn x=q.front(); q.pop(); inq[x.x][x.y]=0;
20         if(x.x!=1&&(d[x.x-1][x.y]==-1||d[x.x-1][x.y]>d[x.x][x.y]+map[x.x-1][x.y])){
21             d[x.x-1][x.y]=d[x.x][x.y]+map[x.x-1][x.y];
22             if(!inq[x.x-1][x.y])inq[x.x-1][x.y]=1,q.push((qn){x.x-1,x.y});
23         }
24         if(x.y!=1&&(d[x.x][x.y-1]==-1||d[x.x][x.y-1]>d[x.x][x.y]+map[x.x][x.y-1])){
25             d[x.x][x.y-1]=d[x.x][x.y]+map[x.x][x.y-1];
26             if(!inq[x.x][x.y-1])inq[x.x][x.y-1]=1,q.push((qn){x.x,x.y-1});
27         }
28         if(x.x!=n&&(d[x.x+1][x.y]==-1||d[x.x+1][x.y]>d[x.x][x.y]+map[x.x+1][x.y])){
29             d[x.x+1][x.y]=d[x.x][x.y]+map[x.x+1][x.y];
30             if(!inq[x.x+1][x.y])inq[x.x+1][x.y]=1,q.push((qn){x.x+1,x.y});
31         }
32         if(x.y!=m&&(d[x.x][x.y+1]==-1||d[x.x][x.y+1]>d[x.x][x.y]+map[x.x][x.y+1])){
33             d[x.x][x.y+1]=d[x.x][x.y]+map[x.x][x.y+1];
34             if(!inq[x.x][x.y+1])inq[x.x][x.y+1]=1,q.push((qn){x.x,x.y+1});
35         }
36     }
37     inc(i,1,n)inc(j,1,m)if(d[i][j]<=k)vis[i][j]=1;
38 }
39 int main(){
40     scanf("%d%d%d",&n,&m,&k); char c;
41     inc(i,1,n)inc(j,1,m){
42         while(!isdigit(c=getchar())); map[i][j]=c-‘0‘;
43     }
44     inc(i,1,n)inc(j,1,m){
45         spfa(i,j); inc(i0,1,n)inc(j0,1,m)if(vis[i0][j0])mx=max(mx,sqrt((i0-i)*(i0-i)+(j0-j)*(j0-j)));
46     }
47     printf("%.6lf",mx); return 0;
48 }

题解:把经过一个障碍物视为边长度为1,求出每两个点之间要跨越的边长度,如果长度小于等于T,就将其欧几里得距离和答案比较。

8、bzoj1221 http://www.lydsy.com/JudgeOnline/problem.php?id=1221

题意:n天,每天需要ai条消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,一条费用fA,B种方式的消毒需要b天,一条费用fB,买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用),求最小费用。n≤1000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 3000
 7 #define INF 0x3fffffff
 8 using namespace std;
 9
10 struct e{int f,t,c,w,n;}; e es[maxn*40]; int ess,g[maxn];
11 inline void pe(int f,int t,int c,int w){
12     es[++ess]=(e){f,t,c,w,g[f]}; g[f]=ess; es[++ess]=(e){t,f,0,-w,g[t]}; g[t]=ess;
13 }
14 void init(){ess=-1; memset(g,-1,sizeof(g));}
15 int d[maxn],fr[maxn]; bool inq[maxn]; queue <int> q;
16 bool spfa(int s,int t){
17     while(!q.empty())q.pop(); memset(inq,0,sizeof(inq)); memset(d,-1,sizeof(d));
18     inq[s]=1; d[s]=0; q.push(s); fr[s]=-1;
19     while(! q.empty()){
20         int x=q.front(); q.pop(); inq[x]=0;
21         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&(d[es[i].t]==-1||d[es[i].t]>d[x]+es[i].w)){
22             d[es[i].t]=d[x]+es[i].w; fr[es[i].t]=i; if(!inq[es[i].t])inq[es[i].t]=1,q.push(es[i].t);
23         }
24     }
25     return d[t]!=-1;
26 }
27 int advanced(int s,int t){
28     int a=INF,c=0;
29     for(int i=fr[t];i!=-1;i=fr[es[i].f])a=min(a,es[i].c);
30     for(int i=fr[t];i!=-1;i=fr[es[i].f])es[i].c-=a,es[i^1].c+=a,c+=(a*es[i].w);
31     return c;
32 }
33 int maxflowmincost(int s,int t){
34     int c=0; while(spfa(s,t))c+=advanced(s,t); return c;
35 }
36 int n,a,b,f,fa,fb,s,t,x;
37 int main(){
38     scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb); s=0; t=2*n+1; init();
39     inc(i,1,n)scanf("%d",&x),pe(s,i,x,0),pe(n+i,t,x,0);
40     inc(i,1,n){
41         if(i+a<n)pe(i,n+i+a+1,INF,fa); if(i+b<n)pe(i,n+i+b+1,INF,fb);
42         if(i<n)pe(i,i+1,INF,0); pe(s,i+n,INF,f);
43     }
44     printf("%d",maxflowmincost(s,t)); return 0;
45 }

题解:费用流。每天拆成x和y。s向所有x连边表示有的毛巾,所有y向t连边表示用的毛巾,流量为需要毛巾数费用0。xi向yi+a连边,表示a方式消毒,xi向yi+b连边,表示b方式消毒,s向所有y连边,表示买新的,xi向xi+1连边,表示前一天没用的拿到第二天用。

反思:费用流关键是要抓住“流量优先”。

9、bzoj1293 http://www.lydsy.com/JudgeOnline/problem.php?id=1293

题意:数轴上N个点,分为K种。可以有多个点出现在同一个位置上。需要一个最短区间使里面有K种点,求这个区间长度。N≤1000000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define INF 0x3fffffff
 6 using namespace std;
 7
 8 struct ball{int a,b;}; ball balls[1000500];
 9 bool cmp(ball a,ball b){return a.a<b.a;}
10 int n,k,l,r,bs,kn[70],ks,mn;
11 int main(){
12     scanf("%d%d",&n,&k);
13     inc(i,1,k){
14         int x,y; scanf("%d",&x); inc(j,1,x)scanf("%d",&y),balls[++bs]=(ball){y,i};
15     }
16     sort(balls+1,balls+1+bs,cmp); l=1; r=0;
17     memset(kn,0,sizeof(kn)); ks=0; mn=INF;
18     while(ks<k){
19         if(r<n){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
20         while(r<n&&balls[r].a==balls[r+1].a){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
21         if(r==n)break;
22     }
23     if(ks==k)mn=min(mn,balls[r].a-balls[l].a);
24     while(1){
25         while(l<r&&balls[l].a==balls[l+1].a){kn[balls[l].b]--; if(kn[balls[l].b]==0)ks--; l++;}
26         if(l<r){kn[balls[l].b]--; if(kn[balls[l].b]==0)ks--; l++;}
27         if(ks==k)mn=min(mn,balls[r].a-balls[l].a);else{
28             while(ks<k){
29                 if(r<n){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
30                 while(r<n&&balls[r].a==balls[r+1].a){r++; kn[balls[r].b]++; if(kn[balls[r].b]==1)ks++;}
31                 if(r==n)break;
32             }
33             if(ks==k)mn=min(mn,balls[r].a-balls[l].a);
34         }
35         if(l==r)break;
36     }
37     printf("%d",mn); return 0;
38 }

题解:先排序,然后用两个指针分别指向区间两个端点,每次l指针往左移并更新答案直到区间里没有K种点,再把r指针向右移直到区间里有K种点,更新一下答案。

20160603

10、bzoj1787 http://www.lydsy.com/JudgeOnline/problem.php?id=1787

题意:给个树,每次给三个点,求与这三个点距离最小的点。点数、询问数≤500000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 500500
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7
 8 inline int read(){
 9     char ch=getchar(); int f=1,x=0;
10     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
11     return x*f;
12 }
13 int fa[maxn][20],dep[maxn];
14 struct e{int t,n;}; e es[maxn*2]; int g[maxn],ess;
15 void pe(int f,int t){
16     es[++ess]=(e){t,g[f]}; g[f]=ess; es[++ess]=(e){f,g[t]}; g[t]=ess;
17 }
18 void init(){ess=0; memset(g,0,sizeof(g));}
19 void dfs(int x,int f){
20     for(int i=g[x];i;i=es[i].n)if(es[i].t!=f){
21         dep[es[i].t]=dep[x]+1; fa[es[i].t][0]=x; dfs(es[i].t,x);
22     }
23 }
24 int n,m;
25 void build(){
26     for(int j=1;(1<<j)<=n;j++)inc(i,1,n)fa[i][j]=fa[fa[i][j-1]][j-1];
27 }
28 int lca(int x,int y){
29     if(dep[x]<dep[y])swap(x,y); int t=dep[x]-dep[y];
30     for(int i=0;(1<<i)<=n;i++)if(t&(1<<i))x=fa[x][i];
31     for(int i=18;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
32     if(x==y)return x;else return fa[x][0];
33 }
34 int dis(int x,int y){
35     int z=lca(x,y); return dep[x]-dep[z]+dep[y]-dep[z];
36 }
37 int main(){
38     n=read(); m=read(); init(); inc(i,1,n-1){int a=read(),b=read(); pe(a,b);}
39     dep[1]=0; fa[1][0]=0; dfs(1,0); build();
40     inc(i,1,m){
41         int a=read(),b=read(),c=read(); int x=lca(a,b),y=lca(a,c),z=lca(b,c);
42         if(x==y)printf("%d %d\n",z,dis(a,z)+dis(b,z)+dis(c,z));
43         else if(x==z)printf("%d %d\n",y,dis(a,y)+dis(b,y)+dis(c,y));
44         else if(y==z)printf("%d %d\n",x,dis(a,x)+dis(b,x)+dis(c,x));
45     }
46     return 0;
47 }

题解:倍增求出两两之间的LCA后,比较容易理解的做法是挑出两个LCA再做一次LCA,比较所有挑法。但画kan出ti图jie可知其中有两个LCA是相等的,而所求就是那个与它们不等的LCA(我也不知为什么)。

11、bzoj1934 http://www.lydsy.com/JudgeOnline/problem.php?id=1934

题意:n个小朋友通过投票来决定睡不睡午觉。每个人都有自己的主见,但也可以投和自己本来意愿相反的票。冲突总数为好朋友之间发生冲突的总数加上和自己本来意愿发生冲突的人数。求最小冲突数。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define maxn 500
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define INF 0x3fffffff
 8 using namespace std;
 9
10 struct e{int t,c,n;}; e es[maxn*2000]; int g[maxn],ess;
11 inline void pe(int f,int t,int c){
12     es[++ess]=(e){t,c,g[f]}; g[f]=ess; es[++ess]=(e){f,0,g[t]}; g[t]=ess;
13 }
14 inline void pe2(int f,int t,int c){
15     es[++ess]=(e){t,c,g[f]}; g[f]=ess; es[++ess]=(e){f,c,g[t]}; g[t]=ess;
16 }
17 inline void init(){
18     ess=-1; memset(g,-1,sizeof(g));
19 }
20 queue <int> q; int h[maxn];
21 bool bfs(int s,int t){
22     memset(h,-1,sizeof(h)); while(!q.empty())q.pop(); h[s]=0; q.push(s);
23     while(! q.empty()){
24         int x=q.front(); q.pop();
25         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==-1)h[es[i].t]=h[x]+1,q.push(es[i].t);
26     }
27     return h[t]!=-1;
28 }
29 int dfs(int x,int t,int f){
30     if(x==t)return f; int u=0;
31     for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==h[x]+1){
32         int w=dfs(es[i].t,t,min(f,es[i].c)); f-=w; u+=w; es[i].c-=w; es[i^1].c+=w; if(f==0)return u;
33     }
34     if(u==0)h[x]=-1; return u;
35 }
36 int dinic(int s,int t){
37     int f=0; while(bfs(s,t))f+=dfs(s,t,INF); return f;
38 }
39 inline int read(){
40     char ch=getchar(); int f=1,x=0;
41     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
42     return x*f;
43 }
44 int n,m,s,t;
45 int main(){
46     n=read(); m=read(); s=0; t=n+1; init(); inc(i,1,n){int x=read(); if(x)pe(s,i,1);else pe(i,t,1);}
47     inc(i,1,m){int x=read(),y=read(); pe2(x,y,1);} printf("%d",dinic(s,t)); return 0;
48 }

题解:最小割,s向每个选1的人连边流量为1,每个选0的人连边流量为1。好朋友之间连流量为1的双向边。

反思:理解错题意……以为冲突总数是每个人投票的冲突数之和,每个人投票冲突数是与朋友之间发生冲突的总数加上和这个人本来意愿发生冲突的人数。脑洞好大QAQ

12、bzoj1452 http://www.lydsy.com/JudgeOnline/problem.php?id=1452

题意:n*m矩阵,支持两个操作,修改某个格子权值和查询某个子矩阵特定权值出现次数。n,m≤300,权值为1到100的整数。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 301
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define lb(x) x&-x
 7 using namespace std;
 8
 9 int sm[maxn][maxn][maxn/3+1],col[maxn][maxn],n,m;
10 void update(int x,int y,int z,int v){
11     for(int i=x;i<=n;i+=lb(i))for(int j=y;j<=m;j+=lb(j))sm[i][j][z]+=v;
12 }
13 int query(int x,int y,int z){
14     int q=0; for(int i=x;i>=1;i-=lb(i))for(int j=y;j>=1;j-=lb(j))q+=sm[i][j][z]; return q;
15 }
16 inline int read(){
17     char ch=getchar(); int f=1,x=0;
18     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
19     return f*x;
20 }
21 int main(){
22     n=read(); m=read(); inc(i,1,n)inc(j,1,m){col[i][j]=read(); update(i,j,col[i][j],1);} int q=read();
23     inc(i,1,q){
24         int x=read();
25         if(x==1){
26             int x0=read(),x1=read(),x2=read();
27             update(x0,x1,col[x0][x1],-1); update(x0,x1,x2,1); col[x0][x1]=x2;
28         }
29         if(x==2){
30             int x1=read(),x2=read(),y1=read(),y2=read(),c=read();
31             printf("%d\n",query(x2,y2,c)-query(x1-1,y2,c)-query(x2,y1-1,c)+query(x1-1,y1-1,c));
32         }
33     }
34     return 0;
35 }

题解:原来二维前缀和也可以用树状数组维护,只要那个不断增加/减少lowbit的循环再嵌套一层就行了。同时因为权值是1到100的整数,所以二维前缀和多一维维护特定权值个数就行了。

13、bzoj1406 http://www.lydsy.com/JudgeOnline/problem.php?id=1406

题意:输出1到n-1中平方后模n等于1的整数

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 100
 7 using namespace std;
 8
 9 int yss,ys[maxn],st[maxn*5000],sts;
10 int main(){
11     int n; scanf("%d",&n); inc(i,1,(int)sqrt(n))if(n%i==0)ys[++yss]=n/i; st[sts=1]=1;
12     inc(i,1,yss){
13         for(int j=ys[i];j<=n;j+=ys[i]){
14             if((j-2)%(n/ys[i])==0)st[++sts]=j-1;
15             if(j<n&&(j+2)%(n/ys[i])==0)st[++sts]=j+1;
16         }
17     }
18     if(sts==0||n==1)printf("None");else{
19         sort(st+1,st+1+sts); int m=unique(st+1,st+1+sts)-st-1; inc(i,1,m)printf("%d\n",st[i]);
20     }
21     return 0;
22 }

题解:设所求数x,化简得(x+1)(x-1)=n*k,设n1*n2等于k,(x+1)%n1==0,(x-1)%n2==0,因此n1、n2都为n的因数,且一个≤sqrt(n),一个≥(sqrt(n))。据说int以内的数的因数都不超过30个,所以可以先求出所有≥sqrt(n)的因数,然后对于每个因数,求出所有<n的这个因数的倍数,用它尝试被x+1模。因为这些因数都≥sqrt(n),所以这个枚举的过程不会超时。

时间: 2024-11-09 02:13:45

20160529~20160604 13的相关文章

【UVALive - 5131】Chips Challenge(上下界循环费用流)

Description A prominent microprocessor company has enlisted your help to lay out some interchangeable components(widgets) on some of their computer chips. Each chip’s design is an N × N square of slots. Oneslot can hold a single component, and you ar

python 各模块

01 关于本书 02 代码约定 03 关于例子 04 如何联系我们 1 核心模块 11 介绍 111 内建函数和异常 112 操作系统接口模块 113 类型支持模块 114 正则表达式 115 语言支持模块 12 _ _builtin_ _ 模块 121 使用元组或字典中的参数调用函数 1211 Example 1-1 使用 apply 函数 1212 Example 1-2 使用 apply 函数传递关键字参数 1213 Example 1-3 使用 apply 函数调用基类的构造函数 122

转:Python标准库(非常经典的各种模块介绍)

Python Standard Library 翻译: Python 江湖群 10/06/07 20:10:08 编译 0.1. 关于本书 0.2. 代码约定 0.3. 关于例子 0.4. 如何联系我们 核心模块 1.1. 介绍 1.2. _ _builtin_ _ 模块 1.3. exceptions 模块 1.4. os 模块 1.5. os.path 模块 1.6. stat 模块 1.7. string 模块 1.8. re 模块 1.9. math 模块 1.10. cmath 模块

13.Linux键盘按键驱动 (详解)

版权声明:本文为博主原创文章,未经博主允许不得转载. 在上一节分析输入子系统内的intput_handler软件处理部分后,接下来我们开始写input_dev驱动 本节目标: 实现键盘驱动,让开发板的4个按键代表键盘中的L.S.空格键.回车键 1.先来介绍以下几个结构体使用和函数,下面代码中会用到 1)input_dev驱动设备结构体中常用成员如下: struct input_dev { void *private; const char *name; //设备名字 const char *ph

JAVA 初识类加载机制 第13节

JAVA 初识类加载机制 第13节 从这章开始,我们就进入虚拟机类加载机制的学习了.那么什么是类加载呢?当我们写完一个Java类的时候,并不是直接就可以运行的,它还要编译成.class文件,再由虚拟机解释给当前的操作系统去执行.这些过程都是我们看不见的,我们能看见的也就是一个.class文件.既然虚拟机要解释这些.class文件给当前的操作系统听,那么他怎么获得这些.class文件呢?虚拟机获得这些.class文件的过程就是类加载了. 所以,总结来说就是:虚拟机将.class文件从磁盘或者其他地

RedHat6.6上安装MySQL5.7.13

由于公司需要更换新的架构,将采用MySQL5.7作为数据库的主要版本,下面将全面介绍在RedHat6.6上二进制安装MySQL5.7.13.后期也将依次介绍在MySQL5.7上的运维管理及优化. 1.下载MySQL5.7.13安装包 下载地址如下,现在的MySQL5.7稳定版已更新到5.7.14 http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.14-linux-glibc2.5-x86_64.tar.gz 2.新建MySQL用户和组

第20章 异常和状态管理20.7-20.13

20.7用可靠性换取开发效率 面向对象编程,编译器功能,CLR功能以及庞大的类库——使.Net Framework成为一个颇具吸引力的开发平台.但所有的这些东西,都会在你的代码中引入你没有什么控制权的“错误点”,如果 OutOfMemoryExcepton等.程序开发不可能对这些异常进行一一捕捉,让应用程序变得绝对健壮.意料意外的异常往往造成程序状态的破坏,为 了缓解对状态的破坏,可以做下面几件事: ●执行catch或finally块时,CLR不允许终止线程,所以可以向下面这样写是Transfe

12.13周记

周数 专业学习目标 专业学习时间 新增代码量 博客发表量 人文方面的学习 知识技能总结 12.13 12.13周web网页制作学习 12周7小时: 13周9小时: 12周300行: 13周400行: 一共发表4篇博客 12.13周<三国志> 12周web中的js应用: 13周C语言的二叉树,以及web中css的应用:

2016年4月13日作业

一.外包管理 1.外包的形式有哪五种?什么是利益关系? 活动外包.服务外包.内包.合包.利益关系 利益关系是一种长期的合作关系,双方先为此关系进行投资,再根据预先拟定的协议分享利益,共同承担风险,同时共享利益. 2.外包管理的目标是什么?要实现这个目标,对外包管理提出哪四个方面的要求? 软件外包管理的总的目标是用强有力的手段来管理同时进行的众多外包项目,满足进度.质量.成本的要求.要实现这个目标就对外包管理提出了以下四方面的要求. 1)慎重选择合格的软件承包商; 2)互相同意对方的承诺; 3)需