fzu 2059 并查集+离线处理

题意:

There is a array contain N(1<N<=100000) numbers. Now give you M(1<M<10000) query.

Every query will be:

1 x : ask longest substring which every number no less than x

2 y x : change the A[y] to x. there are at most change 10 times.

For each ask can you tell me the length of longest substring.

思路:

简单题,因为修改的次数很少。

对于确定的n个数字,可以先把n个数字从小到大排序,然后从大到小依次进行线段块的合并(如果一个点左右的线段块都已经访问过了,说明大小满足覆盖要求),这很适合并查集的特点,所以可以用并查集加个权值,来记录每一块的线段长度。

然后每一次修改之后,就重新进行上面过程。然后之后的每一个查询,都是二分查表即可。(这个地方我想是可以有O(1)的处理方式的)

code:

#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<cctype>
#include<cstdlib>
using namespace std;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define mod 1000000007
typedef pair<int,int> pii;
typedef long long LL;
//------------------------------
const int maxn = 100005;
const int maxm = 10005;

int n,m;
int x[maxm], a[maxn];
struct node{
    int num, id, ans;
    bool operator < (const node nt) const{
        return num < nt.num;
    }
}b[maxn];

int p[maxn], len[maxn];

int find(int x){
    if(x == p[x]) return p[x];
    else return p[x] = find(p[x]);
}
void union_(int u, int v){
    int pu = find(u);
    int pv = find(v);
    if(pu != pv){
        p[pu] = pv;
        len[pv] += len[pu];
    }
}
void deal(){
    for(int i = 1; i <= n; i++){
        b[i].num = a[i];
        b[i].id = i;
    }
    sort(b+1, b+1+n);

    int max_ = 0;
    memset(len, 0, sizeof(len));
    for(int i = 1; i <= n; i++) p[i] = i;
    for(int i = n; i >= 1; i--){
        int id = b[i].id;
        len[id] = 1;
        if(len[id-1]) union_(id-1, id);
        if(len[id+1]) union_(id+1, id);
        if(max_ < len[find(id)]) max_ = len[find(id)];
        b[i].ans = max_;
    }
//    for(int i = 1; i <= n; i++){
//        printf("x = %d   len = %d\n",b[i].num, b[i].ans);
//    }
}
int get_ans(int x){
    node tmp;
    tmp.num = x;
    int id = lower_bound(b+1, b+1+n, tmp) - b;
//    printf("x = %d id = %d\n",x,id);
    return b[id].ans;
}
void solve(){
    int op, a1, a2;
    deal();
    for(int i = 1; i <= m; i++){
        scanf("%d",&op);
        if(op == 2){
            scanf("%d%d",&a1,&a2);
            a[a1] = a2;
            deal();
        }
        if(op == 1){
            scanf("%d",&a1);
            if(a1 > b[n].num){
                printf("0\n");
                continue;
            }
            int ans = get_ans(a1);
            printf("%d\n",ans);
        }
    }
}
int main(){
    while(scanf("%d%d",&n,&m) != EOF){
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
        }
        solve();
    }
    return 0;
}
时间: 2024-10-29 10:25:36

fzu 2059 并查集+离线处理的相关文章

ACM学习历程—SNNUOJ 1110 传输网络((并查集 &amp;&amp; 离线) || (线段树 &amp;&amp; 时间戳))(2015陕西省大学生程序设计竞赛D题)

Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的.现在他们开始在其他城市陆 续建立了新的基站,命令“C x“代表在城市x建立了一个新的基站,不会在同一个城市建立多个基站:城市编号为1到n,其中城市1就是首都Bytetown.在建立基站的过程中他们还 会询问某个城市的网络信号是从哪个城市传输过来的,命令”Q x“代表查询城市x的来源城市. Inpu

FZU 2112 并查集、欧拉通路

原题:http://acm.fzu.edu.cn/problem.php?pid=2112 首先是,票上没有提到的点是不需要去的. 然后我们先考虑这个图有几个联通分量,我们可以用一个并查集来维护,假设有n个联通分量,我们就需要n-1条边把他们连起来. 最后对于每个联通分量来说,我们要使它能一次走完,就是要求他是否满足欧拉通路,也就是这个联通分量中至多有2个度为奇数的点,每多出2个度为奇数的点,就多需要一条边(因为单个连通分量的所有点的度数之和为偶数,所以不可能存在奇数个奇数度数的点). 1 #i

BZOJ 1015 星球大战 并查集+离线

这道题说来真是艰辛,从一开始的RE,到RE,到刚刚的WA,再到AC. 这只能说明我进步的历程,还有我需要不断的加强努力.这道题思路不难,从很久前在黑书中并查集一节就能找到解题的踪影,因为并查集只能并,分不了,所以我们就得离线,倒过来写.只不过这道题真的得审好题目,它问的是剩下的星球中有多少个连通分量,不要搞错了.大概就是这个样子了,加油. 1 #include<cstdio> 2 #include<iostream> 3 #define rep(i,j,k) for(int i=

zoj 3261 Connections in Galaxy War(并查集+离线逆向操作)

 题目:给出一些点,每个点有权值,然后有一些边,相连.无向的.然后有一些操作 query a.表示从a出发的能到达的所有点权值最大的点的编号(相同取编号最小,而且权值要比自己大) destory a,b 表示删除连接a,b的边 思路并查集,但是要逆向处理,所以先离线读入,从后向前处理,于是对于destroy操作,等价于连接两个点的操作,然后对于每个询问输出即可 #include<cstdio> #include<cstring> #include<cmath> #i

hdu5441(并查集+离线处理)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5441 题意: 根据输入的三个整数n.m.q,表示有n座城市,m条路,q次询问.下面给出m行,每行三个数start.end.w,分别是这条道路的起点城市.终点城市."权值".然后给出q次询问的数值,每次询问的结果是符合条件的路有多少条.条件就是:如果这条路的权值比给的限制值要小,那么这条路就是可行的.注意就是:对于一条路的添加来说,只要a到b之间有路,那么符合条件的路就会有两条,一条是a到b

hdu 3938 Portal(并查集+离线+kruskal)

搜了题解才把题搞明白.明白之后发现其实题意很清晰,解题思路也很清晰,只是题目表述的很不清晰…… 大意如下—— 给你一个无向图,图中任意两点的距离是两点间所有路径上的某一条边,这条边需要满足两个条件:1. 这条边这两点间某条路径上的最长边:2. 这条边是这两点间所有路径上的最长边中的最短边. 简单来说,假如a到d有两条路径,一条经过b,一条经过d,其中ab = 1, bd = 3, ac = 2, cd = 2,那么abd上的最长边为3,acd上的最长边为2,则ad的距离为2. 如果a, d两点间

【bzoj1015】【JSOI2008】【星球大战】【并查集+离线】

Description 非常久曾经.在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器.并攻下了星系中差点儿全部的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,非常快帝国又又一次造出了他的超级武器. 凭借这超级武器的力量.帝国開始有计划地摧毁反抗军占领的星球.因为星球的不断被摧毁,两个星球之间的通讯通道也開始不可靠起来.如今,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的

计蒜客 444 / xtuoj 1024 京东的物流路径(并查集+离线lca)

题意:一颗树,定义一条路径的权值等于路径的边权之和,需要求这颗树所有路径中权值的最大值 思路: 考虑到路径权值与点权的最值有关,而最值的问题通常可以通过排序就行处理,于是想到先把点权排序. 容易看出如果某条路径的权值是通过某个点算出的最小 ,那么肯定这条路径肯定不会经过权值更小的点,于是有了两种处理思路 1.按点权从小到大删点,对于即将删除的点,比他权值小的点已经被删去了,所以只要在当前状态的森林里找一条最长路径乘以次点权就可以更新答案 2.按点权从大到小加点,显然新加进来的点权值最小,当前树里

HDU 3938:Portal(并查集+离线处理)

http://acm.hdu.edu.cn/showproblem.php?pid=3938 Portal Problem Description ZLGG found a magic theory that the bigger banana the bigger banana peel .This important theory can help him make a portal in our universal. Unfortunately, making a pair of port