传送门
『郁闷』现在写一道题都要以半天为单位计算时间了= =
数据结构是一个要填的大坑= =之前学过的也只能算是草草学过,没有大量的练习来填坑是不会有提高的= =光打模板题没什么意思= =那么考验码力的时候到了= =
这道题让我明白了怎样用线段树维护连通性。就这道题来说,线段树中的每一个结点都用六个结构体维护一个矩形的连通性(分别是左上右上,左下右下,左上右下,左下右上,左上左下和右上右下),然后update和query的时候会有一些非常奇怪的合并。
主要是想明白一点:判断(x1,y1)(x2,y2)是否连通,所求的路径不一定是在[y1,y2]这个区间里,有可能在区间外面绕一圈又回来了,所以每次query其实需要查询3个区间,然后取一些奇怪的并集。
思路是很好懂的,但是细节十分吃屎= =比如说怎样考虑使每一种情况不重不漏,思维逻辑的缜密十分重要。
再有就是代码能力。刚开始的时候想都没想怒写400行代码,然后发现TLE了。其实是写了很多冗余的东西。后来考虑合并和简化之后又WA一组,最终是一个手残错误= =可见有了思路能否实现也是一个大问题。
贴上可怕的7k代码,TLE
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int max_n=1e5+5;
const int max_tree=max_n*5;
int n,x1,y1,x2,y2;
struct hp{
int luru,lurd,ldru,ldrd,luld,rurd;
}tree[max_tree];
struct hq{
int l,r;
}num[max_tree];
bool up[max_n],down[max_n],list[max_n];
char opt[10];
inline void update(int now){
bool a,b;
//luru
a=tree[now<<1].luru && tree[now<<1|1].luru && up[ num[now<<1].r ];
b=tree[now<<1].lurd && tree[now<<1|1].ldru && down[ num[now<<1].r ];
tree[now].luru=a||b;
//lurd
a=tree[now<<1].luru && tree[now<<1|1].lurd && up[ num[now<<1].r ];
b=tree[now<<1].lurd && tree[now<<1|1].ldrd && down[ num[now<<1].r ];
tree[now].lurd=a||b;
//ldru
a=tree[now<<1].ldru && tree[now<<1|1].luru && up[ num[now<<1].r ];
b=tree[now<<1].ldrd && tree[now<<1|1].ldru && down[ num[now<<1].r ];
tree[now].ldru=a||b;
//ldrd
a=tree[now<<1].ldru && tree[now<<1|1].lurd && up[ num[now<<1].r ];
b=tree[now<<1].ldrd && tree[now<<1|1].ldrd && down[ num[now<<1].r ];
tree[now].ldrd=a||b;
//luld
a=tree[now<<1].luld;
b=tree[now<<1].luru && tree[now<<1].ldrd && tree[now<<1|1].luld && up[ num[now<<1].r ] && down[ num[now<<1].r ];
tree[now].luld=a||b;
//rurd
a=tree[now<<1|1].rurd;
b=tree[now<<1|1].luru && tree[now<<1|1].ldrd && tree[now<<1].rurd && up[ num[now<<1].r ] && down[ num[now<<1].r ];
tree[now].rurd=a||b;
}
inline void build(int now,int l,int r){
int mid=(l+r)>>1;
num[now].l=l; num[now].r=r;
if (l==r){
tree[now].luru=true;
tree[now].lurd=false;
tree[now].ldru=false;
tree[now].ldrd=true;
tree[now].luld=false;
tree[now].rurd=false;
return;
}
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
inline void change(int now,int l,int r,int x){
int mid=(l+r)>>1;
if (l==r){
tree[now].luru=true;
tree[now].lurd=list[l];
tree[now].ldru=list[l];
tree[now].ldrd=true;
tree[now].luld=list[l];
tree[now].rurd=list[l];
return;
}
if (x<=mid)
change(now<<1,l,mid,x);
else
change(now<<1|1,mid+1,r,x);
update(now);
}
inline bool query(int now,int l,int r,int lrange,int rrange,int order){
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange){
switch(order){
case 1:{
return tree[now].luru;
break;
}
case 2:{
return tree[now].ldrd;
break;
}
case 3:{
return tree[now].lurd;
break;
}
case 4:{
return tree[now].ldru;
break;
}
case 5:{
return tree[now].luld;
break;
}
case 6:{
return tree[now].rurd;
break;
}
}
}
bool pd1=false,pd2=false;
bool al,bl,cl,dl,el,fl,ar,br,cr,dr,er,fr;
if (lrange<=mid){
pd1=true;
al=query(now<<1,l,mid,lrange,rrange,1);
bl=query(now<<1,l,mid,lrange,rrange,2);
cl=query(now<<1,l,mid,lrange,rrange,3);
dl=query(now<<1,l,mid,lrange,rrange,4);
el=query(now<<1,l,mid,lrange,rrange,5);
fl=query(now<<1,l,mid,lrange,rrange,6);
}
if (mid+1<=rrange){
pd2=true;
ar=query(now<<1|1,mid+1,r,lrange,rrange,1);
br=query(now<<1|1,mid+1,r,lrange,rrange,2);
cr=query(now<<1|1,mid+1,r,lrange,rrange,3);
dr=query(now<<1|1,mid+1,r,lrange,rrange,4);
er=query(now<<1|1,mid+1,r,lrange,rrange,5);
fr=query(now<<1|1,mid+1,r,lrange,rrange,6);
}
if (pd1&&pd2){
switch(order){
case 1:{
return al&&ar&&up[ num[now<<1].r ] || cl&&dr&&down[ num[now<<1].r ];
break;
}
case 2:{
return dl&&cr&&up[ num[now<<1].r ] || bl&&br&&down[ num[now<<1].r ];
break;
}
case 3:{
return al&&cr&&up[ num[now<<1].r ] || cl&&br&&down[ num[now<<1].r ];
break;
}
case 4:{
return dl&&ar&&up[ num[now<<1].r ] || bl&&dr&&down[ num[now<<1].r ];
break;
}
case 5:{
return el || al&&bl&&er&&up[ num[now<<1].r ]&&down[ num[now<<1].r ];
break;
}
case 6:{
return fr || ar&&br&&fl&&up[ num[now<<1].r ]&&down[ num[now<<1].r ];
break;
}
}
}
if (pd1&&!pd2){
switch(order){
case 1:{
return al;
break;
}
case 2:{
return bl;
break;
}
case 3:{
return cl;
break;
}
case 4:{
return dl;
break;
}
case 5:{
return el;
break;
}
case 6:{
return fl;
break;
}
}
}
if (!pd1&&pd2){
switch (order){
case 1:{
return ar;
break;
}
case 2:{
return br;
break;
}
case 3:{
return cr;
break;
}
case 4:{
return dr;
break;
}
case 5:{
return er;
break;
}
case 6:{
return fr;
break;
}
}
}
if (!pd1&&!pd2) return false;
}
inline bool ask(int x1,int y1,int x2,int y2){
//1:luru 2:ldrd 3:lurd 4:ldru 5:luld 6:rurd
bool a,b,c,d,e,f;
a=query(1,1,n,x1,x2,1);
b=query(1,1,n,x1,x2,2);
c=query(1,1,n,x1,x2,3);
d=query(1,1,n,x1,x2,4);
e=query(1,1,n,1,x1,6);
f=query(1,1,n,x2,n,5);
if (y1==0&&y2==0){
return a || d&&e || c&&f || b&&e&&f;
}
if (y1==1&&y2==1){
return b || c&&e || d&&f || a&&e&&f;
}
if (y1==0&&y2==1){
return c || a&&f || b&&e || d&&e&&f;
}
if (y1==1&&y2==0){
return d || a&&e || b&&f || c&&e&&f;
}
}
int main(){
// freopen("input.txt","r",stdin);
scanf("%d",&n);
memset(up,0,sizeof(up));
memset(down,0,sizeof(down));
build(1,1,n);
while (scanf("%s",opt)!=EOF){
if (opt[0]=='E') break;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
swap(x1,y1);
swap(x2,y2);
if (x1>x2){
swap(x1,x2);
swap(y1,y2);
}
--y1; --y2;
// cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
if (opt[0]=='O'){
if (x1==x2){
list[x1]=true;
change(1,1,n,x1);
}
else{
if (y1==0){
up[x1]=true;
change(1,1,n,x1);
change(1,1,n,x2);
}
else{
down[x1]=true;
change(1,1,n,x1);
change(1,1,n,x2);
}
}
}
if (opt[0]=='C'){
if (x1==x2){
list[x1]=false;
change(1,1,n,x1);
}
else{
if (y1==0){
up[x1]=false;
change(1,1,n,x1);
change(1,1,n,x2);
}
else{
down[x1]=false;
change(1,1,n,x1);
change(1,1,n,x2);
}
}
}
if (opt[0]=='A'){
bool ans=ask(x1,y1,x2,y2);
if (ans) printf("Y\n");
else printf("N\n");
}
}
/* for (int i=1;i<n;++i) printf("%d%c",up[i]," \n"[i==n-1]); for (int i=1;i<n;++i) printf("%d%c",down[i]," \n"[i==n-1]); for (int i=1;i<=n;++i) printf("%d%c",list[i]," \n"[i==n]); */
}
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int max_n=1e5+5;
const int max_tree=max_n*5;
int n,x1,y1,x2,y2;
struct hp{
int luru,lurd,ldru,ldrd,luld,rurd;
}tree[max_tree];
struct hq{
bool a,b,c,d,e,f;
};
int num[max_tree];
bool up[max_n],down[max_n],list[max_n];
char opt[10];
inline void update(int now){
bool a,b;
//luru
a=tree[now<<1].luru && tree[now<<1|1].luru && up[ num[now<<1] ];
b=tree[now<<1].lurd && tree[now<<1|1].ldru && down[ num[now<<1] ];
tree[now].luru=a||b;
//lurd
a=tree[now<<1].luru && tree[now<<1|1].lurd && up[ num[now<<1] ];
b=tree[now<<1].lurd && tree[now<<1|1].ldrd && down[ num[now<<1] ];
tree[now].lurd=a||b;
//ldru
a=tree[now<<1].ldru && tree[now<<1|1].luru && up[ num[now<<1] ];
b=tree[now<<1].ldrd && tree[now<<1|1].ldru && down[ num[now<<1] ];
tree[now].ldru=a||b;
//ldrd
a=tree[now<<1].ldru && tree[now<<1|1].lurd && up[ num[now<<1] ];
b=tree[now<<1].ldrd && tree[now<<1|1].ldrd && down[ num[now<<1] ];
tree[now].ldrd=a||b;
//luld
a=tree[now<<1].luld;
b=tree[now<<1].luru && tree[now<<1].ldrd && tree[now<<1|1].luld && up[ num[now<<1] ] && down[ num[now<<1] ];
tree[now].luld=a||b;
//rurd
a=tree[now<<1|1].rurd;
b=tree[now<<1|1].luru && tree[now<<1|1].ldrd && tree[now<<1].rurd && up[ num[now<<1] ] && down[ num[now<<1] ];
tree[now].rurd=a||b;
}
inline void build(int now,int l,int r){
int mid=(l+r)>>1;
// cout<<now<<endl;
if (l==r){
tree[now].luru=true;
tree[now].lurd=false;
tree[now].ldru=false;
tree[now].ldrd=true;
tree[now].luld=false;
tree[now].rurd=false;
num[now]=r;
return;
}
num[now]=r;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
inline void change(int now,int l,int r,int x){
int mid=(l+r)>>1;
if (l==r){
tree[now].luru=true;
tree[now].lurd=list[l];
tree[now].ldru=list[l];
tree[now].ldrd=true;
tree[now].luld=list[l];
tree[now].rurd=list[l];
return;
}
if (x<=mid)
change(now<<1,l,mid,x);
else
change(now<<1|1,mid+1,r,x);
update(now);
}
inline hq query(int now,int l,int r,int lrange,int rrange){
int mid=(l+r)>>1;
hq ans;
hq L,R;
bool pd1=false,pd2=false;
if (lrange<=l&&r<=rrange)
return ans=(hq){tree[now].luru,tree[now].ldrd,tree[now].lurd,
tree[now].ldru,tree[now].luld,tree[now].rurd};
if (lrange<=mid){
pd1=true;
L=query(now<<1,l,mid,lrange,rrange);
}
if (mid+1<=rrange){
pd2=true;
R=query(now<<1|1,mid+1,r,lrange,rrange);
}
if (pd1&&pd2){
bool a,b,c,d,e,f;
a=L.a&&R.a&&up[ num[now<<1] ] || L.c&&R.d&&down[ num[now<<1] ];
b=L.d&&R.c&&up[ num[now<<1] ] || L.b&&R.b&&down[ num[now<<1] ];
c=L.a&&R.c&&up[ num[now<<1] ] || L.c&&R.b&&down[ num[now<<1] ];
d=L.d&&R.a&&up[ num[now<<1] ] || L.b&&R.d&&down[ num[now<<1] ];
e=L.e || L.a&&L.b&&R.e&&up[ num[now<<1] ]&&down[ num[now<<1] ];
f=R.f || R.a&&R.b&&L.f&&up[ num[now<<1] ]&&down[ num[now<<1] ];
return ans=(hq){a,b,c,d,e,f};
}
if (pd1&&!pd2)
return ans=(hq){L.a,L.b,L.c,L.d,L.e,L.f};
if (!pd1&&pd2)
return ans=(hq){R.a,R.b,R.c,R.d,R.e,R.f};
if (!pd1&&!pd2) return ans=(hq){false,false,false,false,false,false};
}
inline bool ask(int x1,int y1,int x2,int y2){
hq now,l,r;
now=query(1,1,n,x1,x2);
l=query(1,1,n,1,x1);
r=query(1,1,n,x2,n);
if (y1==0&&y2==0)
return now.a || now.d&&l.f || now.c&&r.e || now.b&&l.f&&r.e;
if (y1==1&&y2==1)
return now.b || now.c&&l.f || now.d&&r.e || now.a&&l.f&&r.e;
if (y1==0&&y2==1)
return now.c || now.a&&r.e || now.b&&l.f || now.d&&l.f&&r.e;
if (y1==1&&y2==0)
return now.d || now.a&&l.f || now.d&&r.e || now.c&&l.f&&r.e;
}
int main(){
scanf("%d",&n);
memset(up,0,sizeof(up));
memset(down,0,sizeof(down));
build(1,1,n);
int cnt=0;
while (scanf("%s",opt)!=EOF){
if (opt[0]=='E') break;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
swap(x1,y1);
swap(x2,y2);
if (x1>x2){
swap(x1,x2);
swap(y1,y2);
}
--y1; --y2;
if (opt[0]=='O'){
if (x1==x2){
list[x1]=true;
change(1,1,n,x1);
}
else{
if (y1==0){
up[x1]=true;
change(1,1,n,x1);
change(1,1,n,x2);
}
else{
down[x1]=true;
change(1,1,n,x1);
change(1,1,n,x2);
}
}
}
if (opt[0]=='C'){
if (x1==x2){
list[x1]=false;
change(1,1,n,x1);
}
else{
if (y1==0){
up[x1]=false;
change(1,1,n,x1);
change(1,1,n,x2);
}
else{
down[x1]=false;
change(1,1,n,x1);
change(1,1,n,x2);
}
}
}
if (opt[0]=='A'){
cnt++;
bool ans=ask(x1,y1,x2,y2);
if (ans) printf("Y\n");
else printf("N\n");
}
}
return 0;
}
用线段树维护连通性有了新的经验。
对冗余的简化。
码力++