8
24
2016
0

[BZOJ3757] 苹果树

怎么交都是RE

找来hzwer的程序RE

找来PoPoQQQ的程序RE

找来ww140142的程序RE

一开始我还以为自己写错了

毁我AC率

-------------------------

树上莫队

我没用王室联邦的分块方法,我写了一个块状树的版本

目前莫名RE

等我要到数据再修复……

-------------------------

本机怎么测都AC(Lemon)

以为是爆栈了写个手工栈照样RE

把数组放大10倍还是RE

不管了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=50005,M=100005,block_size=300,T=17;

int n,m,color[N],en,h[N],belong[N],cnt[N],dfn[N],indexs[N],colornum,dep[N],L,R,fa[N][20],Index,siz[N],block_cnt,ans[N],root;

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

struct Edge{
int b,next;
}e[M];

struct Queries{
int l,r,a,b,id;
friend inline bool operator<(const Queries &A,const Queries &B){return belong[A.l]<belong[B.l] || (belong[A.l]==belong[B.l] && dfn[A.r]<dfn[B.r]);}
}que[M];

inline void AddEdge(const int &sa,const int &sb){e[++en].b=sb;e[en].next=h[sa];h[sa]=en;}

inline void Add(const int &x){cnt[x]++;if(cnt[x]==1)colornum++;}
inline void Del(const int &x){cnt[x]--;if(cnt[x]==0)colornum--;}
inline void Change(const int &x){if(indexs[x])Del(color[x]);else Add(color[x]);indexs[x]^=1;}

void dfs(int u,int f){
dfn[u]=++Index;fa[u][0]=f;
if(siz[belong[f]]==block_size)belong[u]=++block_cnt;
else belong[u]=belong[f];
siz[belong[u]]++;dep[u]=dep[f]+1;
for(int i=h[u];i;i=e[i].next){
    int v=e[i].b;
    if(v==f)continue;
    dfs(v,u);
}
}

inline void Prepare(){
for(register int i=1;i<=T;i++){
    for(register int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];
}
}

inline int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int deep=dep[u]-dep[v];
for(register int i=T;~i;i--)if(deep&(1<<i))u=fa[u][i];
for(register int i=T;~i;i--)if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
return u==v?u:fa[u][0];
}

int main(){
freopen("3757.in","r",stdin);
freopen("3757.out","w",stdout);
Read(n);Read(m);
for(register int i=1;i<=n;i++)Read(color[i]);
for(register int i=1;i<=n;i++){int u,v;Read(u);Read(v);if(u==0 || v==0)root=u+v;else AddEdge(u,v),AddEdge(v,u);}
dfs(root,0);
Prepare();
for(register int i=1;i<=m;i++){
    Read(que[i].l);Read(que[i].r);Read(que[i].a);Read(que[i].b);que[i].id=i;
    if(dfn[que[i].l]>dfn[que[i].r])swap(que[i].l,que[i].r);
}
sort(que+1,que+m+1);L=R=root;
for(register int i=1;i<=m;i++){
    int y=LCA(que[i].l,L);
	for(int j=que[i].l;j!=y;j=fa[j][0])Change(j);
	for(int j=L;j!=y;j=fa[j][0])Change(j);
	y=LCA(que[i].r,R);
	for(int j=que[i].r;j!=y;j=fa[j][0])Change(j);
	for(int j=R;j!=y;j=fa[j][0])Change(j);
	L=que[i].l;R=que[i].r;
    int x=LCA(L,R);
    Change(x);
    ans[que[i].id]=colornum;
    if(cnt[que[i].a] && cnt[que[i].b] && que[i].a!=que[i].b)ans[que[i].id]--;
    Change(x);
}
for(register int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
Category: BZOJ | Tags: OI bzoj
8
21
2016
0

[BZOJ3036] 绿豆蛙的归宿

考虑dp

设$d[x]$为到达$x$号点时的期望长度

因为会随机选一个点,所以到达$x$号点的期望长度为所有能到x号点的点的期望长度乘以到达x号点的边长度

这就告诉我们需要拓扑排序

首先边反向(这样不用处理根本到不了终点的点,而且可以避免计算错误)

(当然反向是比正向快多了)(我正向TLE了)

然后直接在拓扑序上面搞就行

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int N=100005;

int n,m,h[N],en,nxt[N];
double d[N],p[N];
queue<int> Q;

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

struct Edge{int b,v,next;}e[N<<1];
inline void AddEdge(const int &sa,const int &sb,const int &sc){e[++en].b=sb;nxt[sb]++;e[en].v=sc;e[en].next=h[sa];h[sa]=en;}

inline void bfs(){
for(register int i=1;i<=n;i++)p[i]=1.0/nxt[i];
Q.push(n);
while(!Q.empty()){
	int u=Q.front();Q.pop();
	for(register int i=h[u];i;i=e[i].next){
		int v=e[i].b;
		d[v]+=p[v]*(d[u]+e[i].v);
		if(!--nxt[v])Q.push(v);
	}
}
}

int main(){
freopen("3036.in","r",stdin);
freopen("3036.out","w",stdout);
Read(n);Read(m);
for(register int i=1;i<=m;i++){
	int u,v,w;
    Read(u);Read(v);Read(w);
    AddEdge(v,u,w);
}
bfs();
printf("%.2lf\n",d[1]);
return 0;
}
Category: BZOJ | Tags: OI bzoj
8
20
2016
0

[BZOJ1419] Red is good

设$dp[i][j]$为有i张红j张黑时的期望最大值

因为随时可以停止所以当期望小于0时直接改成0

同时因为会爆空间所以改成滚动数组

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=5005;

int R,B;
double dp[2][N];

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

int main(){
freopen("1419.in","r",stdin);
freopen("1419.out","w",stdout);
Read(R);Read(B);
for(register int i=1;i<=R;i++){
	int now=i&1,pre=now^1;
	dp[now][0]=i;
	for(register int j=1;j<=B;j++){
		double Px=1.0*i/(i+j);
		dp[now][j]=Px*(dp[pre][j]+1)+(1-Px)*(dp[now][j-1]-1);
		if(dp[now][j]<0)dp[now][j]=0;
	}
}
printf("%.6lf\n",dp[R&1][B]-0.0000005);
return 0;
}
Category: BZOJ | Tags: OI bzoj
8
20
2016
0

[BZOJ3809] Gty的二逼妹子序列

明天就要上课了

这题是一个莫队+分块

据说莫队+树状数组会T掉

所以我就把整个答案按照权值分块卡卡常就做完了

目前bzoj用时为$20808ms$

数组开小wa两次我真是太弱了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005,block=300;

int n,m,s[N],ans[N*10],cnt[N],bk[N];

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

inline int Gi(const int &x){return (x-1)/block+1;}

struct Query{
int l,r,a,b,id;
friend inline bool operator<(const Query &A,const Query &B){return Gi(A.l)<Gi(B.l)||(Gi(A.l)==Gi(B.l) && A.r<B.r);}
}que[N*10];

inline void Up(int x){
cnt[s[x]]++;
if(cnt[s[x]]==1)bk[Gi(s[x])]++;
}

inline void Down(int x){
cnt[s[x]]--;
if(cnt[s[x]]==0)bk[Gi(s[x])]--;
}

inline int Q(const int &l,const int &r){
int ls=Gi(l)+1,rs=Gi(r)-1,lv=Gi(l)*block,rv=(Gi(r)-1)*block+1,ans=0;
if(ls-rs==2)for(register int i=l;i<=r;i++)ans+=(cnt[i]>0);
else {
	for(register int i=ls;i<=rs;i++)ans+=bk[i];
	for(register int i=l;i<=lv;i++)ans+=(cnt[i]>0);
	for(register int i=rv;i<=r;i++)ans+=(cnt[i]>0);
}
return ans;
}

int main(){
freopen("3809.in","r",stdin);
freopen("3809.out","w",stdout);
Read(n);Read(m);
for(register int i=1;i<=n;i++)Read(s[i]);
for(register int i=1;i<=m;i++)Read(que[i].l),Read(que[i].r),Read(que[i].a),Read(que[i].b),que[i].id=i;
sort(que+1,que+m+1);
register int L=1,R=0;
for(register int i=1;i<=m;i++){
	while(L>que[i].l)Up(--L);
	while(L<que[i].l)Down(L++);
	while(R>que[i].r)Down(R--);
	while(R<que[i].r)Up(++R);
    ans[que[i].id]=Q(que[i].a,que[i].b);
}
for(register int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
Category: BZOJ | Tags: OI bzoj
8
19
2016
0

[hihoCoder1225] 向日葵

题解clj大神有了就不放了

链接

一道非常好的题目,只是调试能死人罢了

注意要点:

1.此时的极角排序必须加上象限的判断不然会出错(重要!)

2.注意每次point数组必须清空而不能复用因为编号乱了

3.以后数组开到原来的4倍左右防止因数组开小而出错

4.使用long long类型可以有效避免精度误差

5.以后碰到这种题我就写一个$O(n^3)$的暴力,因为这题数据很良心是可以过的,而且我考场上几乎100%不能调试成功

下面版本复杂度为$O(n^2logn)$

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=4005;
const double eps=1e-17;

int n,cnt,ind[N];
double ans;

struct Point{
long long x,y;
int id;
Point(){}
Point(long long _x,long long _y){x=_x;y=_y;}
friend inline Point operator+(const Point &A,const Point &B){return Point(A.x+B.x,A.y+B.y);}
friend inline Point operator-(const Point &A,const Point &B){return Point(A.x-B.x,A.y-B.y);}
friend inline long long operator*(const Point &A,const Point &B){return A.x*B.y-A.y*B.x;}
friend inline bool operator==(const Point &A,const Point &B){return A.x==B.x && A.y==B.y;}
}ChosenPoint,point[N<<1];

inline int Check(Point A){
if(A.x-ChosenPoint.x>0 && A.y-ChosenPoint.y>=0)return 0;
if(A.x-ChosenPoint.x<=0 && A.y-ChosenPoint.y>0)return 1;
if(A.x-ChosenPoint.x<0 && A.y-ChosenPoint.y<=0)return 2;
return 3;
}

inline int Dist2(const Point &A,const Point &B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);}
inline bool cmp(const Point &A,const Point &B){int x=Check(A),y=Check(B);if(x!=y)return x<y;return (A-ChosenPoint)*(B-ChosenPoint)>=0;}
inline bool OnRight(const Point &A,const Point &B,const Point &C){return (B-A)*(C-A)>=0;}

struct Pair_Points{
Point A,B;
}poi[N];

int main(){
freopen("1225.in","r",stdin);
freopen("1225.out","w",stdout);
scanf("%d",&n);
if(n<3){puts("0.000000");return 0;}
for(int i=1;i<=n;i++)scanf("%lld %lld %lld %lld",&poi[i].A.x,&poi[i].A.y,&poi[i].B.x,&poi[i].B.y);
for(int i=1;i<=n;i++){
	ChosenPoint=poi[i].A;
	cnt=0;
	for(int j=1;j<=n;j++){
		if(i==j)continue;
		point[++cnt]=poi[j].A;point[cnt].id=j;point[++cnt]=poi[j].B;point[cnt].id=j;
	}
	sort(point+1,point+cnt+1,cmp);
	memset(ind,0,sizeof(ind));
	int cntx[3]={n-1},pos=1;
	for(int j=cnt+1;j<=2*cnt;j++)point[j]=point[j-cnt];
	for(int j=1;j<=cnt;j++){
		while(pos<j+cnt && OnRight(ChosenPoint,point[j],point[pos])){
			ind[point[pos].id]++;
			cntx[ind[point[pos].id]]++;
			cntx[ind[point[pos].id]-1]--;
            pos++;
		}
		//printf("%d %d %d %d\n", pos, cntx[0], cntx[1], cntx[2]);
		if(cntx[1]+cntx[2]==n-1){
			double afk=0.125;
			if(ind[point[j].id]==1)afk/=pow(2,cntx[1]-1);
			else afk/=pow(2,cntx[1]);
			ans+=afk*(ChosenPoint*point[j]);
		}
		ind[point[j].id]--;
		cntx[ind[point[j].id]]++;
		cntx[ind[point[j].id]+1]--;
	}
}
for(int i=1;i<=n;i++){
	ChosenPoint=poi[i].B;
	cnt=0;
	for(int j=1;j<=n;j++){
		if(i==j)continue;
		point[++cnt]=poi[j].A;point[cnt].id=j;point[++cnt]=poi[j].B;point[cnt].id=j;
	}
	sort(point+1,point+cnt+1,cmp);
	memset(ind,0,sizeof(ind));
	int cntx[3]={n-1},pos=1;
	for(int j=cnt+1;j<=2*cnt;j++)point[j]=point[j-cnt];
	for(int j=1;j<=cnt;j++){
		while(pos<j+cnt && OnRight(ChosenPoint,point[j],point[pos])){
			ind[point[pos].id]++;
			cntx[ind[point[pos].id]]++;
			cntx[ind[point[pos].id]-1]--;
            pos++;
		}
		//printf("%d %d %d %d\n", pos, cntx[0], cntx[1], cntx[2]);
		if(cntx[1]+cntx[2]==n-1){
			double afk=0.125;
			if(ind[point[j].id]==1)afk/=pow(2,cntx[1]-1);
			else afk/=pow(2,cntx[1]);
			ans+=afk*(ChosenPoint*point[j]);
		}
		ind[point[j].id]--;
		cntx[ind[point[j].id]]++;
		cntx[ind[point[j].id]+1]--;
	}
}
printf("%.17lf\n",ans);
return 0;
}
Category: 其他OJ | Tags: OI hihoCoder
8
17
2016
0

[UOJ222] 【NOI2016】区间

two points+线段树

按长度排序之后一个个加就行

我考场上居然没想到

数组开小wa了2次……身败名裂

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=500005,INF=1000000000;

int b[N<<1],n,m,cnt,ans=INF,tot;

struct Inside{
int l,r,len;
friend bool operator<(const Inside &A,const Inside &B){return A.len<B.len;}
}ins[N];

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

struct SegTree{
int l,r,tag,cnt;
}tree[N<<3];

inline void Pushup(const int &rt){
tree[rt].cnt=tree[rt].tag+max(tree[rt<<1].cnt,tree[rt<<1|1].cnt);
}

void Build(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;
if(l==r)return;
int mid=l+r>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
}

void Add(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r){tree[rt].cnt++;tree[rt].tag++;return;}
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Add(rt<<1,l,r);
if(r>mid)Add(rt<<1|1,l,r);
Pushup(rt);
}

void Del(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r){tree[rt].cnt--;tree[rt].tag--;return;}
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Del(rt<<1,l,r);
if(r>mid)Del(rt<<1|1,l,r);
Pushup(rt);
}

int main(){
freopen("222.in","r",stdin);
freopen("222.out","w",stdout);
Read(n);Read(m);
for(int i=1;i<=n;i++){
	Read(ins[i].l);Read(ins[i].r);
	ins[i].len=ins[i].r-ins[i].l;
	b[++cnt]=ins[i].l;b[++cnt]=ins[i].r;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=n;i++)ins[i].l=lower_bound(b+1,b+cnt+1,ins[i].l)-b,ins[i].r=lower_bound(b+1,b+cnt+1,ins[i].r)-b;
sort(ins+1,ins+n+1);
Build(1,1,cnt);
int cur=0;
for(int i=1;i<=n;i++){
    while(cur<n && tree[1].cnt<m){cur++;Add(1,ins[cur].l,ins[cur].r);}
    if(tree[1].cnt<m)break;
    ans=min(ans,ins[cur].len-ins[i].len);
    Del(1,ins[i].l,ins[i].r);
}
printf("%d\n",ans==INF?-1:ans);
return 0;
}
Category: 其他OJ | Tags: OI uoj
8
16
2016
0

UOJ Round #15 题解

这次比赛我打的很不好……其实是因为懒

没写暴力

当时做掉了A,BC当时不会做,现在也不会做

所以暂时只有A的题解

A.奥林匹克五子棋

我们思考怎么摆放最优

首先我们发现每一行的摆放是否连通只和上一行的摆放方式有关

所以我们要尽量减少连通

想让上下不联通得左右放

想让左右不联通得上下放

那么我们就得到了一种摆放的方式

0101010101

0101010101

1010101010

1010101010

这样就可以完成目标了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

int n,m,k;
queue<pair<int,int> > Q1,Q2;

int Abs(int x){return x>0?x:-x;}

int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d %d %d",&n,&m,&k);
if(k==1){puts("-1");return 0;}
else if(k==2){if(n<2 || m<2){if(n==1)for(int i=1;i<=m;i++)printf("%d %d\n",1,i);else if(m==1)for(int i=1;i<=n;i++)printf("%d %d\n",i,1);}else puts("-1");return 0;}
else if(k>min(n,m)){
	for(int i=1;i<=n;i++){
        if(i%2){if(m%2)for(int j=1;j<=m;j++)printf("%d %d\n",i,j);else for(int j=m;j;j--)printf("%d %d\n",i,j);}
        else for(int j=1;j<=m;j++)printf("%d %d\n",i,j);
	}
	return 0;
}
else if(k>2){
	for(int i=1;i<=n;i++){
		if(i%4==1 || i%4==2){for(int j=1;j<=m;j++){if(j&1)Q1.push(make_pair(i,j));else Q2.push(make_pair(i,j));}}
		else {for(int j=1;j<=m;j++){if(j&1)Q2.push(make_pair(i,j));else Q1.push(make_pair(i,j));}}
	}
	if(Abs(Q1.size()-Q2.size())>=2){
		while(!Q1.empty())Q1.pop();
		while(!Q2.empty())Q2.pop();
		swap(n,m);
		for(int i=1;i<=n;i++){
			if(i%4==1 || i%4==2){for(int j=1;j<=m;j++){if(j&1)Q1.push(make_pair(j,i));else Q2.push(make_pair(j,i));}}
			else {for(int j=1;j<=m;j++){if(j&1)Q2.push(make_pair(j,i));else Q1.push(make_pair(j,i));}}
		}
		if(Abs(Q1.size()-Q2.size())>=2){puts("-1");return 0;}
		else {
            int x=n*m,flg=1;
			while(x--){
				if(flg){printf("%d %d\n",Q1.front().first,Q1.front().second);Q1.pop();}
				else {printf("%d %d\n",Q2.front().first,Q2.front().second);Q2.pop();}
				flg^=1;
			}
		}
	}
	else {
		int x=n*m,flg=1;
		while(x--){
			if(flg){printf("%d %d\n",Q1.front().first,Q1.front().second);Q1.pop();}
			else {printf("%d %d\n",Q2.front().first,Q2.front().second);Q2.pop();}
			flg^=1;
		}
	}
	return 0;
}
return 0;
}

B.奥林匹克环城马拉松

正在思考中

C.奥林匹克数据结构

正在思考中

 

Category: 比赛 | Tags: 比赛 OI uoj
8
16
2016
0

Codeforces Round #367 (Div. 2) 题解

订正完了就发一下题解吧

第一次写比赛题解

当时我在比赛时A掉了ABCD,E没敢写链表就GG了

所以我订正完后来发一下

A.Beru-taxi

模拟即可

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

int a,b,n,pos;
double t=21000000000000000.0;

double Dist(int x,int y,int z){return sqrt(1.0*(x-a)*(x-a)+(y-b)*(y-b))/(1.0*z);}

int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d %d",&a,&b);
scanf("%d",&n);
for(int i=1;i<=n;i++){
	int tx,ty,s;
	scanf("%d %d %d",&tx,&ty,&s);
    t=min(Dist(tx,ty,s),t);
}
printf("%.6lf\n",t);
return 0;
}

B.Interesting drink

虽然有线性做法但是二分显然更好写吧……那就写二分

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005;

int n,a[N],m;

int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1);
scanf("%d",&m);
while(m--){
	int x;
	scanf("%d",&x);
    printf("%d\n",upper_bound(a+1,a+n+1,x)-a-1);
}
return 0;
}

C.Hard problem

这不是暴力比较就好了?然后做一个贪心(请无视我的数组名)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005;

int n,pos[N];
long long dp[N][2],c[N];
char str[N];

bool Big_Small(int x,int inv1,int y,int inv2){
if(!inv1 && !inv2){
	int px=pos[y];
	for(int i=pos[x];i<pos[x+1];i++,px++){
		if(px>=pos[y+1])return 0;
		if(str[i]<str[px])return 1;
		else if(str[i]>str[px])return 0;
	}
	return 1;
}
if(inv1 && !inv2){
	int px=pos[y];
	for(int i=pos[x+1]-1;i>=pos[x];i--,px++){
		if(px>=pos[y+1])return 0;
		if(str[i]<str[px])return 1;
		else if(str[i]>str[px])return 0;
	}
	return 1;
}
if(!inv1 && inv2){
	int px=pos[y+1]-1;
	for(int i=pos[x];i<pos[x+1];i++,px--){
		if(px<pos[y])return 0;
		if(str[i]<str[px])return 1;
		else if(str[i]>str[px])return 0;
	}
	return 1;
}
if(inv1 && inv2){
	int px=pos[y+1]-1;
	for(int i=pos[x+1]-1;i>=pos[x];i--,px--){
		if(px<pos[y])return 0;
		if(str[i]<str[px])return 1;
		else if(str[i]>str[px])return 0;
	}
	return 1;
}
}

int main(){
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%I64d",&c[i]);
pos[1]=1;
memset(dp,127,sizeof(dp));
for(int i=1;i<=n;i++){
	scanf("%s",str+pos[i]);
	pos[i+1]=strlen(str+1)+1;
}
dp[1][0]=0;dp[1][1]=c[1];
for(int i=2;i<=n;i++){
	if(Big_Small(i-1,0,i,0))dp[i][0]=min(dp[i-1][0],dp[i][0]);
	if(Big_Small(i-1,0,i,1))dp[i][1]=min(dp[i-1][0]+c[i],dp[i][1]);
	if(Big_Small(i-1,1,i,0))dp[i][0]=min(dp[i-1][1],dp[i][0]);
	if(Big_Small(i-1,1,i,1))dp[i][1]=min(dp[i-1][1]+c[i],dp[i][1]);
}
long long px=min(dp[n][0],dp[n][1]);
printf("%I64d\n",px>=21000000000000000ll?-1ll:px);
return 0;
}

D.Vasiliy's Multiset

字典树裸题……没有任何难度

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=200005;

int n,x,st[32],cnt=1;
char str[10];

struct Trie{
int ch[2],num;
}tree[7000005];

void Num(int x){
for(int i=31;i>=0;i--)st[i+1]=(x&(1<<i))>=1;
}

void Add(){
int rt=1;
for(int i=32;i;i--){
	if(!tree[rt].ch[st[i]])tree[rt].ch[st[i]]=++cnt;
	tree[tree[rt].ch[st[i]]].num++;
	rt=tree[rt].ch[st[i]];
}
}

void Del(){
int rt=1;
for(int i=32;i;i--){
	if(!tree[rt].ch[st[i]])tree[rt].ch[st[i]]=++cnt;
	tree[tree[rt].ch[st[i]]].num--;
	rt=tree[rt].ch[st[i]];
}
}

int Ask(){
int rt=1;
for(int i=32;i;i--){
	if(tree[tree[rt].ch[!st[i]]].num){rt=tree[rt].ch[!st[i]];st[i]=1;}
	else if(tree[tree[rt].ch[st[i]]].num){rt=tree[rt].ch[st[i]];st[i]=0;}
	else {break;}
}
int x=0;
for(int i=1;i<=32;i++){x|=(st[i]<<(i-1));/*printf("%d\n",x);*/}
return x;
}

int main(){
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
scanf("%d",&n);
Add();
while(n--){
	int x;
	scanf("%s %d",str,&x);
    Num(x);
    //for(int i=32;i;i--)printf("%d ",st[i]);
	//putchar('\n');
    if(str[0]=='+')Add();
	if(str[0]=='-')Del();
	if(str[0]=='?')printf("%d\n",Ask());
}
return 0;
}

E.Working routine

使用十字链表维护整个矩阵,每次修改只改边缘的就好了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=1005;

int n,m,mat[N][N],q;

struct Value{
Value *up,*down,*left,*right;
int v;
Value(int x){up=down=left=right=NULL;v=x;}
}*root[N],*Upx[N],*Upy[N],*Downx[N],*Downy[N],*Leftx[N],*Lefty[N],*Rightx[N],*Righty[N];

inline void Initialize(){
for(int i=1;i<=n;i++){
	Value *tp;
	for(int j=1;j<=m;j++){
		if(j==1){
			root[i]=new Value(mat[i][j]);
			tp=root[i];
		}
		else {
			tp->right=new Value(mat[i][j]);
			tp->right->left=tp;
            tp=tp->right;
		}
	}
}
}

inline void Build(){
Value *tp[N];
tp[0]=tp[n+1]=NULL;
for(int i=1;i<=n;i++)tp[i]=root[i];
for(int i=1;i<=m;i++){
	for(int j=1;j<=n;j++){tp[j]->up=tp[j-1];tp[j]->down=tp[j+1];}
	for(int j=1;j<=n;j++)tp[j]=tp[j]->right;
}
}

inline void SelectX(Value *r[N],int x,int y,int len){
Value *tp=root[x];
for(int i=1;i<y;i++)tp=tp->right;
for(int i=1;i<=len;i++){r[i]=tp;tp=tp->right;}
}

inline void SelectY(Value *r[N],int x,int y,int len){
Value *tp=root[x];
for(int i=1;i<y;i++)tp=tp->right;
for(int i=1;i<=len;i++){r[i]=tp;tp=tp->down;}
}

inline void PrintMatrix(){
for(int i=1;i<=n;i++){
	Value *cur;
	for(int j=1;j<=m;j++){
		if(j==1)cur=root[i];
		else cur=cur->right;
		printf("%d ",cur->v);
	}
	putchar('\n');
}
}

inline void Change(int l1,int r1,int l2,int r2,int h,int w){
Value *tp;
SelectX(Upx,l1,r1,w);
SelectX(Upy,l2,r2,w);
SelectX(Downx,l1+h-1,r1,w);
SelectX(Downy,l2+h-1,r2,w);
SelectY(Leftx,l1,r1,h);
SelectY(Lefty,l2,r2,h);
SelectY(Rightx,l1,r1+w-1,h);
SelectY(Righty,l2,r2+w-1,h);
//for(int i=1;i<=h;i++)printf("%d ",Leftx[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Lefty[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Rightx[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Righty[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Upx[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Upy[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Downx[i]->v);
//for(int i=1;i<=h;i++)printf("%d ",Downy[i]->v);
//putchar('\n');
for(int i=1;i<=h;i++){
    if(Leftx[i]->left && Lefty[i]->left){Leftx[i]->left->right=Lefty[i];Lefty[i]->left->right=Leftx[i];tp=Leftx[i]->left;Leftx[i]->left=Lefty[i]->left;Lefty[i]->left=tp;}
    else if(Leftx[i]->left && !Lefty[i]->left){Lefty[i]->left=Leftx[i]->left;Leftx[i]->left->right=Lefty[i];Leftx[i]->left=NULL;root[l2+i-1]=Leftx[i];}
    else if(!Leftx[i]->left && Lefty[i]->left){Leftx[i]->left=Lefty[i]->left;Lefty[i]->left->right=Leftx[i];Lefty[i]->left=NULL;root[l1+i-1]=Lefty[i];}
    else if(!Leftx[i]->left && !Lefty[i]->left){root[l1+i-1]=Lefty[i];root[l2+i-1]=Leftx[i];}
	if(Rightx[i]->right && Righty[i]->right){Rightx[i]->right->left=Righty[i];Righty[i]->right->left=Rightx[i];tp=Rightx[i]->right;Rightx[i]->right=Righty[i]->right;Righty[i]->right=tp;}
    else if(Rightx[i]->right && !Righty[i]->right){Righty[i]->right=Rightx[i]->right;Rightx[i]->right->left=Righty[i];Rightx[i]->right=NULL;}
    else if(!Rightx[i]->right && Righty[i]->right){Rightx[i]->right=Righty[i]->right;Righty[i]->right->left=Rightx[i];Righty[i]->right=NULL;}
}
for(int i=1;i<=w;i++){
	if(Upx[i]->up && Upy[i]->up){Upx[i]->up->down=Upy[i];Upy[i]->up->down=Upx[i];tp=Upx[i]->up;Upx[i]->up=Upy[i]->up;Upy[i]->up=tp;}
    else if(Upx[i]->up && !Upy[i]->up){Upx[i]->up->down=Upy[i];Upy[i]->up=Upx[i]->up;Upx[i]->up=NULL;}
    else if(!Upx[i]->up && Upy[i]->up){Upx[i]->up=Upy[i]->up;Upy[i]->up->down=Upx[i];Upy[i]->up=NULL;}
	if(Downx[i]->down && Downy[i]->down){Downx[i]->down->up=Downy[i];Downy[i]->down->up=Downx[i];tp=Downx[i]->down;Downx[i]->down=Downy[i]->down;Downy[i]->down=tp;}
    else if(Downx[i]->down && !Downy[i]->down){Downy[i]->down=Downx[i]->down;Downx[i]->down->up=Downy[i];Downx[i]->down=NULL;}
    else if(!Downx[i]->down && Downy[i]->down){Downx[i]->down=Downy[i]->down;Downy[i]->down->up=Downx[i];Downy[i]->down=NULL;}
}
}

int main(){
freopen("E.in","r",stdin);
freopen("E.out","w",stdout);
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&mat[i][j]);
Initialize();
Build();
while(q--){
	int l1,r1,l2,r2,h,w;
    scanf("%d %d %d %d %d %d",&l1,&r1,&l2,&r2,&h,&w);
    Change(l1,r1,l2,r2,h,w);
}
PrintMatrix();
return 0;
}

这次Div2真是水的可怕……

 

Category: 比赛 | Tags: OI 比赛
8
10
2016
0

[BZOJ3483] SGU505 Prefixes and suffixes(询问在线版)

考虑维护可持久化线段树+字典树

首先建出两个字典树(一正一反),求一下dfs序然后就变成了查询当前字符串在这两个字典树中区间的共有值

我们可以利用可持久化线段树来支持查询

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=2005,M=2000005;

int n,ans,len,posA[N],posB[N],root[N*25],l[N*25],r[N*25],v[N*25],cnt,en,h[M],m;
char s[M],ch;

inline void Read_Decrypt(){
while((ch=getchar())<'a' || ch>'z');
s[len=1]=(ch-'a'+ans)%26;
while((ch=getchar())>='a' && ch<='z')s[++len]=(ch-'a'+ans)%26;
}

struct Edge{
int b,next;
}e[N];

inline void AddEdge(int sa,int sb){e[++en].b=sb;e[en].next=h[sa];h[sa]=en;}

struct Trie{
int son[M][26],cnt,dfn,st[M],ed[M];
inline int ins0();
inline int ins1();
void dfs(int x);
inline pair<int,int> ask0();
inline pair<int,int> ask1();
}A,B;

inline int Trie::ins0(){
int x=0;
for(int i=1;i<=len;i++){
	if(!son[x][s[i]])son[x][s[i]]=++cnt;
	x=son[x][s[i]];
}
return x;
}

inline int Trie::ins1(){
int x=0;
for(int i=len;i;i--){
	if(!son[x][s[i]])son[x][s[i]]=++cnt;
	x=son[x][s[i]];
}
return x;
}

void Trie::dfs(int x){
st[x]=++dfn;
for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i]);
ed[x]=dfn;
}

inline pair<int,int> Trie::ask0(){
int x=0;
for(int i=1;i<=len;i++){
	if(!son[x][s[i]])return make_pair(0,0);
	x=son[x][s[i]];
}
return make_pair(st[x],ed[x]);
}

inline pair<int,int> Trie::ask1(){
int x=0;
for(int i=len;i;i--){
	if(!son[x][s[i]])return make_pair(0,0);
	x=son[x][s[i]];
}
return make_pair(st[x],ed[x]);
}

inline int Insert(int x,int a,int b,int p){
int y=++cnt;v[y]=v[x]+1;
if(a==b)return y;
int mid=a+b>>1;
if(p<=mid)l[y]=Insert(l[x],a,mid,p),r[y]=r[x];
else l[y]=l[x],r[y]=Insert(r[x],mid+1,b,p);
return y;
}

inline int Query(int x,int a,int b,pair<int,int> p){
if(!x)return 0;
if(p.first<=a && b<=p.second)return v[x];
int mid=a+b>>1,ans=0;
if(p.first<=mid)ans+=Query(l[x],a,mid,p);
if(p.second>mid)ans+=Query(r[x],mid+1,b,p);
return ans;
}

int main(){
freopen("3483.in","r",stdin);
freopen("3483.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
    Read_Decrypt();
    posA[i]=A.ins0();posB[i]=B.ins1();
}
A.dfs(0);B.dfs(0);
for(int i=1;i<=n;i++)AddEdge(A.st[posA[i]],B.st[posB[i]]);
for(int i=1;i<=A.dfn;i++){
	root[i]=root[i-1];
	for(int j=h[i];j;j=e[i].next)root[i]=Insert(root[i],1,B.dfn,e[j].b);
}
scanf("%d",&m);
while(m--){
    pair<int,int> L,R;
    Read_Decrypt();
    L=A.ask0();
    Read_Decrypt();
    R=B.ask1();
    if(L.first && R.first)ans=Query(root[L.second],1,B.dfn,R)-Query(root[L.first-1],1,B.dfn,R);
    else ans=0;
    printf("%d\n",ans);
}
return 0;
}
Category: BZOJ | Tags: OI bzoj
8
4
2016
0

[UOJ3] 【NOI2014】魔法森林

sbLCT调了这么长时间……

Splay部分写错了

按照a从小到大排序,用LCT维护最小生成树

没了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=50005,INF=1000000000;

int n,m,ans=INF;

struct Node{
int v,id;
bool rev;
Node *ch[2],*fa,*mxe;
Node();
void Pushdown();
void Pushup();
}*tree[N<<2],*Null;

struct Ed{
int u,v,a,b;
friend bool operator<(const Ed &A,const Ed &B){return A.a<B.a||(A.a==B.a && A.b<B.b);}
}es[N<<1];

Node::Node(){fa=ch[0]=ch[1]=Null;mxe=this;v=-INF;rev=id=0;}

inline void Node::Pushdown(){
if(rev){
	if(ch[0]!=Null)ch[0]->rev^=1;
	if(ch[1]!=Null)ch[1]->rev^=1;
    swap(ch[0],ch[1]);
    rev=0;
}
}

inline void Node::Pushup(){
mxe=this;
if(ch[0]->mxe->v>mxe->v)mxe=ch[0]->mxe;
if(ch[1]->mxe->v>mxe->v)mxe=ch[1]->mxe;
}

inline bool Notroot(Node *x){return x->fa->ch[0]==x || x->fa->ch[1]==x;}
inline void Prepare(Node *x){if(Notroot(x))Prepare(x->fa);x->Pushdown();}

void Rotate(Node *x,int kind){
Node *y=x->fa,*z=y->fa;
y->ch[!kind]=x->ch[kind];
if(x->ch[kind]!=Null)x->ch[kind]->fa=y;
x->fa=z;
if(Notroot(y))z->ch[z->ch[1]==y]=x;
y->fa=x;
x->ch[kind]=y;
y->Pushup();
x->Pushup();
}

void Splay(Node *x){
Prepare(x);
while(Notroot(x)){
	Node *y=x->fa,*z=y->fa;
    if(!Notroot(y))Rotate(x,y->ch[0]==x);
    else {
        if(y->ch[0]==x && z->ch[0]==y){Rotate(y,1);Rotate(x,1);}
        else if(y->ch[0]==x && z->ch[1]==y){Rotate(x,1);Rotate(x,0);}
        else if(y->ch[1]==x && z->ch[0]==y){Rotate(x,0);Rotate(x,1);}
        else {Rotate(y,0);Rotate(x,0);}
    }
}
}

void Access(Node *x){for(Node *y=Null;x!=Null;y=x,x=x->fa){Splay(x);x->ch[1]=y;x->Pushup();}}
void Makeroot(Node *x){Access(x);Splay(x);x->rev^=1;}
void Link(Node *x,Node *y){Makeroot(x);x->fa=y;}
void Cut(Node *x,Node *y){Makeroot(x);Access(y);Splay(y);y->ch[0]=x->fa=Null;y->Pushup();}
Node *Find(Node *x){Access(x);Splay(x);while(x->ch[0]!=Null)x=x->ch[0];return x;}
Node *GetNull(){Node *p=new Node();p->ch[0]=p->ch[1]=p->fa=p->mxe=p;return p;}
Node *Query(Node *x,Node *y){Makeroot(x);Access(y);Splay(y);return y->mxe;}

int main(){
freopen("3.in","r",stdin);
freopen("3.out","w",stdout);
scanf("%d %d",&n,&m);
Null=GetNull();
for(int i=1;i<=m;i++)scanf("%d %d %d %d",&es[i].u,&es[i].v,&es[i].a,&es[i].b);
sort(es+1,es+m+1);
for(int i=1;i<=n;i++)tree[i]=new Node();
for(int i=1;i<=m;i++)tree[i+n]=new Node(),tree[i+n]->v=es[i].b,tree[i+n]->id=i;
for(int i=1;i<=m;i++){
    if(es[i].u==es[i].v)continue;
	if(Find(tree[es[i].u])==Find(tree[es[i].v])){
		Node *c=Query(tree[es[i].u],tree[es[i].v]);
		if(c->v>es[i].b){Cut(tree[es[c->id].u],c);Cut(tree[es[c->id].v],c);}
		else {if(Find(tree[1])==Find(tree[n]))ans=min(ans,es[i].a+Query(tree[1],tree[n])->v);continue;}
	}
    Link(tree[es[i].u],tree[i+n]);Link(tree[es[i].v],tree[i+n]);
    if(Find(tree[1])==Find(tree[n])){ans=min(ans,es[i].a+Query(tree[1],tree[n])->v);}
}
printf("%d\n",ans==INF?-1:ans);
return 0;
}
Category: 其他OJ | Tags: OI uoj

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com