您的位置:首页 > 运维架构

UVALive 6265 Graphic Madness 搜索 Regionals 2012 :: Europe - Central

2015-08-24 09:07 323 查看
其他题做法:

Non-boring sequences

求是否任意子串中,都有一个数,这个数只出现一次:

方法:跟矩形面积并一样,从右到左做,用线段树维护,对于i位置,如果线段树中恰好有n-i+1个点被覆盖了,说明

有解,否则无解。

如何构造线段?: 对于a(1)......a(i).......(N)括号里的数字表示位置,a表示一个数

有两个a,对于a(2)如果已经走过i位置,且目前在j位置j>1,那么可以知道[i,N]这个区间,[j ,x] ,x属于[i,N],a都是唯一的,因此对[i,N]加入一条线段

当到位置1时删除[i,N],加入[1,i-1]如此更新即可,

当然:还有通过类似快排的方法过的,但是也要通过记录每个数字前面,后面出现时的位置,

这样能确定一个数在这个区间是不是唯一的。

方法就是,对于一个区间,如果有一个唯一的数字,那么可以分成左右两个区间,分别判断即可。

注意会有超时的情况,数据是特殊构造的,既然是快排,如果只从一个方向开始,就会卡你

因此考虑一个分界点从两个方向同时进行判定,这样容易比较快找到分界点。

构造数据如下:

............DCDBCAB.

这种数据每次只能找到一个分界点,而且区间的规模只会是原来的N-2,会T掉(如果从左到右处理)

如果两个方向一起来,就很快找到分界点 了。跟快排的随机取点一样。贴一个队友的代码:线段树做的

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

const int maxn = (int)2e5+100;
struct tree{
	int c, sum;
}t[maxn<<2];
int a[maxn], p[maxn], last[maxn], nxt[maxn];
int T, n, size;

inline void update(int x, int l, int r){
	if (t[x].c > 0){ t[x].sum = r - l + 1; }
	else if (l == r){ t[x].sum = 0; }
	else t[x].sum = t[x<<1].sum + t[x<<1|1].sum;
}
void build(int x, int l, int r){
	t[x].c = t[x].sum = 0;
	if (l == r) return;
	int mid = l + r >> 1;
	build(x<<1, l, mid);
	build(x<<1|1, mid+1, r);
}

void insert(int x, int L, int R, int val, int l, int r){
	if (L <= l && r <= R){
		t[x].c += val;
		update(x, l, r);
		return;
	}
	int mid = l + r >> 1;
	if (L <= mid) insert(x<<1, L, R, val, l, mid);
	if (mid < R) insert(x<<1|1, L, R, val, mid+1, r);
	update(x, l, r);
}
char msg[2][15] = {"boring", "non-boring"};
int main()
{
	scanf("%d", &T);
	while(T--){
		bool flag = true;
		scanf("%d", &n);
		size = 0;
		for (int i = 0; i < n; i++){
			scanf("%d", &a[i]);
			p[size++] = a[i];
		}
		sort(p, p+size);
		size = unique(p, p+size) - p;
		for (int i = 0; i < n; i++){ a[i] = lower_bound(p, p+size, a[i]) - p; }
		for (int i = 0; i < size; i++) last[i] = n;
		for (int i = n-1; i >= 0; i--){
			nxt[i] = last[a[i]];
			last[a[i]] = i;
		}
//		puts("");
//		for (int i = 0; i < n; i++)
//			printf("%d\n", nxt[i]);
		build(1, 0, n-1);
		for (int i = n-1; i >= 0; i--){
			if (nxt[i] != n) insert(1, nxt[i], nxt[nxt[i]]-1, -1, 0, n-1);
			insert(1, i, nxt[i]-1, 1, 0, n-1);
//			printf("%d %d\n", i, t[1].sum);
			if (t[1].sum < n-1-i+1){ flag = false; break; }
		}
		printf("%s\n", msg[flag]);
	}
	return 0;
}


求一条路径走过两个树的所有点,并回到起点的方案。不存在输出NO。

两棵树的叶子结点是相互连通的,并且叶子结点相同,并且是一一对应的关系。

做法:先把两个树分成链,树要能分成不相交的链,起点终点都在叶子结点,那么就可以下一步了。

否则无解。判断的方法是任意非叶子点深搜一次,

记录need值,表示根为u的子树,有几个u的子树需要通过根才能连到其他叶子结点。

如果need>2说明无解,因为只能有一条路径经过u,

如果need=1说明u必须通过父亲才能连到其他结点。

分成链以后,对图进行一次深搜,一定会搜出一个环,判断环的大小是否恰好等于点数总和。

是就有解,输出即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
struct Edge{
    int u,v,next,use;
    Edge(){}
    void init(int _u,int _v,int _next,int _use){
        u =_u;
        v = _v;
        next = _next;
        use = _use;
    }
};
#define maxn 50000
Edge edge[maxn];
int cnt,head[maxn];
void addedge(int u,int v){
    edge[cnt].init(u,v,head[u],0);
    head[u] = cnt++;
    edge[cnt].init(v,u,head[v],0);
    head[v] = cnt++;
}

int ty[maxn];
char word[20];
int work(){
    int u=0;
    scanf("%s",word);
    if(word[0] == 'B') u+=4000;
    if(word[1] == 'S') u+=2000;
    int t = 0,len=strlen(word);
    for(int i = 2;i < len; i++)
        t = t*10+word[i]-'0';
    return u+t;
}
int ans;
int dfs(int u,int f){
    int need = 0,t;
    for(int i = head[u];i != -1; i= edge[i].next){
        int v = edge[i].v;
        if(v == f) continue;
        t = dfs(v,u);
        need += t;
        if(need > 2) ans = 0;
        if(t == 0) {
            edge[i].use = 1;
            edge[i^1].use = 1;
        }
    }
    if(need == 2) return 0;
    return 1;
}
int check[maxn];
vector<int>loop;
int dfs2(int u){
    if(check[u]) return 0;
    loop.push_back(u);
    check[u] = 1;
    for(int i = head[u]; i != -1;i=edge[i].next){
        int v = edge[i].v;
        if(edge[i].use == 0 && check[v] == 0){
            return dfs2(v)+1;
        }
    }
    return 1;
}

int main(){
    int t,n,k,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&k,&n,&m);
        memset(head,-1,sizeof(head));
        cnt = 0;
        int u,v;
        for(int i = 0;i < n+k-1; i++){
            u = work();
            v = work();
            addedge(u,v);
        }
        ans = 1;
        dfs(1,0);

        for(int i = 0;i < m+k-1; i++){
            u = work();
            v = work();
            addedge(u,v);
        }
        if(ans) dfs(4001,0);

        for(int i = 0;i < k; i++){
            u = work();
            v = work();
            addedge(u,v);
        }

        memset(check,0,sizeof(check));
        loop.clear();
        if(ans) {
            u = dfs2(1);
            if(u != n+k+k+m) ans = 0;
        }
        if(ans == 1){
            printf("YES");
            for(int i = 0;i < loop.size(); i++){
                printf(" ");
                if(loop[i] / 4000 == 0) printf("A");
                else printf("B");
                if(loop[i] % 4000 > 2000 ) printf("S");
                else printf("P");
                printf("%d",loop[i]%2000);

            }
            printf("\n");
        }
        else puts("NO");
    }
    return 0;
}

/*
1
2 1 11
AS1 AP1
AS2 AP1

BS1 BP1
BS2 BP11
BP1 BP2
BP2 BP3
BP3 BP4
BP4 BP5
BP5 BP6
BP6 BP7
BP7 BP8
BP8 BP9
BP9 BP10
BP10 BP11

AS1 BS2
BS1 AS2
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: