• HDU 4630、BOJ 某题


    两道离线线段树。

    比赛时候没想到。。。。

    扫描数组,i从1到n,线段树维护从1到i每一个约数(1~50000)的出现的最近位置,线段树存储的是约数的最大值

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    
    using namespace std;
    
    const int N=50050;
    
    struct Interval{
        int l,r,id;
    }in[N];
    
    struct Tree{
        int l,r,Max;
    }tree[N<<2];
    
    int n,m;
    int a[N];
    int pre[N];
    int ans[N];
    vector<int> factor[N];
    
    
    void init(){
        for(int i=1;i<N;i++)
            for(int j=i;j<N;j+=i)
                factor[j].push_back(i);
    }
    
    bool cmp(struct Interval a,struct Interval b){
        return a.r<b.r;
    }
    
    void build(int l,int r,int id){
        tree[id].l=l;
        tree[id].r=r;
        tree[id].Max=0;
        if(l!=r){
            int mid=(l+r)>>1;
            build(l,mid,id<<1);
            build(mid+1,r,id<<1|1);
        }
    }
    
    void update(int pos,int val,int id){
        tree[id].Max=max(tree[id].Max,val);
        if(tree[id].l==tree[id].r) return ;
        int mid=(tree[id].l+tree[id].r)>>1;
        if(mid>=pos) update(pos,val,id<<1);
        else update(pos,val,id<<1|1);
    }
    
    int query(int l,int r,int id){
        if(tree[id].l==l && tree[id].r==r) return tree[id].Max;
        int mid=(tree[id].l+tree[id].r)>>1;
        if(mid>=r) return query(l,r,id<<1);
        else if(mid<l) return query(l,r,id<<1|1);
        else return max(query(l,mid,id<<1),query(mid+1,r,id<<1|1));
    }
    
    int main(){
        init();
        int t,T;
        int i,j,k;
        scanf("%d",&T);
        for(t=1;t<=T;t++){
            scanf("%d",&n);
            build(1,n,1);
            for(i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            scanf("%d",&m);
            for(i=0;i<m;i++){
                scanf("%d %d",&in[i].l,&in[i].r);
                in[i].id=i;
            }
            sort(in,in+m,cmp);
            memset(pre,0,sizeof(pre));
            for(i=1,j=0;i<=n && j<m;i++){
                for(k=0;k<factor[a[i]].size();k++){
                    int tem=factor[a[i]][k];
                    if(pre[tem]!=0){
                        update(pre[tem],tem,1);
                    }
                    pre[tem]=i;
                }
                while(j<m && in[j].r==i){
                    ans[in[j].id]=query(in[j].l,in[j].r,1);
                    j++;
                }
            }
            for(i=0;i<m;i++) printf("%d
    ",ans[i]);
        }
        return 0;
    }



    BOJ的那题找不到了,做完这道题之后,发现这两题很像,都是离线线段树做法。(这道题还是队友出的,膜拜)


    先为数组中每个点i一个最小区间l,r满足a[i]>a[l] && a[i]<a[r],l<i<r

    然后i从1开始扫描,每次把能加入的点加入,然后处理右端点为i的查询

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    using namespace std;
    const int MAXN = 100000+5;
    const int INF = 0x3f3f3f3f;
    int T, N, Q, a[MAXN], s[MAXN], t[MAXN];
    int idq[MAXN], q[MAXN], cnt[MAXN], p[MAXN];
    int x[MAXN], y[MAXN], ida[MAXN];
    int Tr[MAXN<<2], mark[MAXN<<2];
    void Build(int idx, int L, int R)
    {
    	Tr[idx] = mark[idx] = 0;
    	if (L == R)
    		return;
    	int left = idx<<1, right = idx<<1|1, mid = (L+R)>>1;
    	Build(left, L, mid);
    	Build(right, mid+1, R);
    }
    void PushDown(int idx)
    {
    	int left = idx<<1, right = idx<<1|1, &mk = mark[idx];
    	Tr[left] += mk;
    	mark[left] += mk;
    	Tr[right] += mk;
    	mark[right] += mk;
    	mk = 0;
    }
    void Update(int idx, int L, int R, int l, int r, int c)
    {
    	if (l <= L && R <= r)
    	{
    		Tr[idx] += c;
    		mark[idx] += c;
    		return;
    	}
    	if (mark[idx])
    		PushDown(idx);
    	int left = idx<<1, right = idx<<1|1, mid = (L+R)>>1;
    	if (l <= mid)
    		Update(left, L, mid, l, r, c);
    	if (mid < r)
    		Update(right, mid+1, R, l, r, c);
    }
    int Query(int idx, int L, int R, int x)
    {
    	if (x == L && R == x)
    		return Tr[idx];
    	if (mark[idx])
    		PushDown(idx);
    	int left = idx<<1, right = idx<<1|1, mid = (L+R)>>1;
    	if (x <= mid)
    		return Query(left, L, mid, x);
    	else
    		return Query(right, mid+1, R, x);
    }
    bool cmpq(const int &a, const int &b)
    {
    	return t[a] < t[b];
    }
    bool cmpa(const int &a, const int &b)
    {
    	return y[a] < y[b];
    }
    int main()
    {
    	//freopen("data.in", "r", stdin);
    	//freopen("data.out", "w", stdout);
    	scanf("%d", &T);
    	for (int cas = 1; cas <= T; cas++)
    	{
    		printf("Case %d:
    ", cas);
    		scanf("%d", &N);
    		stack<int> stal, star;
    		a[0] = 0;
    		stal.push(0);
    		for (int i = 1; i <= N; i++)
    		{
    			scanf("%d", &a[i]);
    			while (a[i] <= a[stal.top()])
    				stal.pop();
    			x[i] = stal.top();
    			stal.push(i);
    		}
    		a[N+1] = INF;
    		star.push(N+1);
    		for (int i = N; i >= 1; i--)
    		{
    			while (a[i] >= a[star.top()])
    				star.pop();
    			y[i] = star.top();
    			star.push(i);
    			ida[i] = i;
    		}
    		sort(ida+1, ida+1+N, cmpa);
    		scanf("%d", &Q);
    		for (int i = 1; i <= Q; i++)
    		{
    			scanf("%d%d", &s[i], &t[i]);
    			if (s[i] > t[i])
    				swap(s[i], t[i]);
    			idq[i] = i;
    			q[i] = 0;
    		}
    		sort(idq+1, idq+1+Q, cmpq);
    		Build(1, 1, N);
    		for (int i = 1, j = 1, k = 1; i <= N; i++)
    		{
    			for (; y[ida[k]] == i && k <= N; k++) if (x[ida[k]])
    				Update(1, 1, N, 1, x[ida[k]], 1);
    			for (; t[idq[j]] == i && j <= Q; j++)
    				q[idq[j]] = Query(1, 1, N, s[idq[j]]);
    		}
    		for (int i = 1; i <= Q; i++)
    			printf("%d
    ", q[i]);
    	}
    	return 0;
    }
    


  • 相关阅读:
    217MySQL读写分离mysqlproxy
    shell脚本自动化安装LAMP
    Mybatis的如何根据下划线_,百分号%模糊查询escape的作用
    springboot下MVC的MessageConverters和静态资源位置的配置
    全局性事务控制如何在springboot中配置
    最详细的@Transactional讲解
    常用网址
    truncate、drop、delete区别
    CommandLineRunner、ApplicationRunner 接口
    交叉编译,为什么需要交叉编译
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3231056.html
Copyright © 2020-2023  润新知