首页 > 其他分享 >区间不同数的个数 二维数点 扫描线 可持久化线段树

区间不同数的个数 二维数点 扫描线 可持久化线段树

时间:2023-04-30 11:11:04浏览次数:49  
标签:int 线段 数点 tr eve cin 扫描线 event

二维数点,对于询问的\([l, r]\)区间我们只需要统计有多少个数上一次出现的位置\(pos\) 满足\(pos \leq l\),即可。

template<class T>
struct BIT {
    T c[N];
    int size;
    void resize(int s) { size = s;}
    T query(int x) { // 1 ... x
        assert(x <= size);
        T s = 0;
        for (; x; x -= x & (-x)) {
            s += c[x];
        }
        return s;
    }

    void modify(int x, T s) { // a[x] += s
        assert(x != 0);
        for (; x <= size; x += x & (-x)) {
            c[x] += s;
        }
    } 
};
BIT<int> tr;
int n, q, pos[N];
int a[N], ans[N];
vector<pii> qu[N];
void solve()
{   
    cin>>n;
    for(int i = 1; i <= n; i++)   cin>>a[i];
    cin>>q;
 	for(int i = 1; i <= q; i++)
	{
		int l, r;	cin>>l>>r;
		qu[r].pb({l, i});
	} 
	tr.resize(n);
	for(int r = 1; r <= n; r++)
	{
		int last = pos[a[r]];
		tr.modify(last + 1, 1);
		tr.modify(r + 1, -1);
		for(auto it : qu[r])
			ans[it.second] = tr.query(it.fi);
		pos[a[r]] = r; 
	}
 	for(int i = 1; i <= q; i++)
 		cout<<ans[i]<<endl;
 
    return;
}

扫描线

对数组预处理这个数上一次出现的位置,然后进行常规的扫描线操作

为什么(代码这样写)可以这样做,区间\([l,r]\)答案为\([1,r] - [1, l - 1]\),而在排序中,我们数组存的第一关键字是上一次出现的位置,所以始终第一个出现在\([l,r]\)区间的数会快询问一步在树状数组进行modify,保证一个数只会被算到一次

template<class T>
struct BIT {
    T c[N];
    int size;
    void resize(int s) { size = s;}
    T query(int x) { // 1 ... x
        assert(x <= size);
        T s = 0;
        for (; x; x -= x & (-x)) {
            s += c[x];
        }
        return s;
    }

    void modify(int x, T s) { // a[x] += s
        assert(x != 0);
        for (; x <= size; x += x & (-x)) {
            c[x] += s;
        }
    } 
};
BIT<int> tr;
void solve()
{   
    cin>>n;
    for(int i = 1; i <= n; i++)   
    {
        cin>>a[i];
        event.pb({pre[a[i]], 0, i});
        pre[a[i]] = i;
    }
    cin>>q;
    for(int i = 1; i <= q; i++)
    {
        int l, r;    cin>>l>>r;
        event.pb({l, -1, r, i});
    }
    sort(all(event));
    tr.resize(n);
    for(auto eve : event)
    {
        if(eve[1] == 0)
        {
            tr.modify(eve[2], 1);
        }
        else
        {
            ans[eve[3]] -= tr.query(eve[0] - 1);
            ans[eve[3]] += tr.query(eve[2]);
        }
    }
    for(int i = 1; i <= q; i++)
        cout<<ans[i]<<endl;
    return;
}

标签:int,线段,数点,tr,eve,cin,扫描线,event
From: https://www.cnblogs.com/magicat/p/17365044.html

相关文章

  • 权值线段树模板
    【模板】普通平衡树//AConemoretimes#include<bits/stdc++.h>usingnamespacestd;#definefifirst#definesesecond#definepbpush_back#defineendl'\n'#defineall(x)(x).begin(),(x).end()typedefpair<int,int>pii;constint......
  • 线段树
     1.基础算法1.1快读快写template<typenameT>inlinevoidread(T&t){​ intf=0,c=getchar();t=0;​ while(!isdigit(c))f|=c=='-',c=getchar();​ while(isdigit(c))t=t*10+c-48,c=getchar();​ if(f)t=-t;​}​​templ......
  • 线段树的动态开点模板
    学习自数据结构学习笔记(5)动态开点线段树动态开点线段树感谢大佬们博客的帮助//AConemoretimes#include<bits/stdc++.h>usingnamespacestd;#definefifirst#definesesecond#definepbpush_back#defineendl'\n'#defineall(x)(x).begin(),(x).end()......
  • CF960F Pathwalks | 线段树优化DP
    题目设\(dp[x,w]\)为以结点\(x\)为结尾,且最后一条边边权为\(w\)的最长路径长度。考虑根据顺序加边,对于边\((u,v)\),更新\[dp[v,w]=\max_{w'<w}\{dp[u,w']\}+1\]对于每个节点,建一棵线段树,维护\(dp[x]\),这样每次更新\(dp[v,w]\)就相当于在\(dp[u]\)所对应的线段树中查询\([......
  • 线段树
    1#include<iostream>2#include<string>3#definelllonglong4constintN=1e5+5;56usingnamespacestd;78lltree[N<<2];//线段树,可以是对应的结构体9lllz[N<<2];//延迟标记,也可以是结构体1011//lz标记下传12voidpush_down(intid......
  • C# 小数转百分比以及小数转字符串精确小数点
    模拟游戏中相乘减伤计算staticvoidTest(){Calc(newdouble[]{0.1,0.3,0.2,0.17,0.5});}staticvoidCalc(double[]arr){doubletotal=1;foreach(vardinarr){total*=(1-d......
  • HDU - 5649 线段树+区间二分答案 (好题)
    DZYhasasequencea[1…n].Itisapermutationofintegers1∼n.Nowhewantstoperformtwotypesofoperations:0lr:Sorta[l…r]inincreasingorder.1lr:Sorta[l…r]indecreasingorder.Afterdoingalltheoperations,hewilltellyouapositionk,andask......
  • [Week 18] 每日一题(C++,动态规划,线段树,数学)
    目录[Daimayuan]T1最长公共子序列(C++,DP,二分)输入格式输出格式数据范围输入样例输出样例解题思路[Daimayuan]T2喵喵序列(C++,序偶)题目描述输入格式输出格式样例输入样例输出样例说明数据范围双倍经验解题思路:[Daimayuan]T3漂亮数(C++,字符串)输入描述输出描述输入样例输出样例解题......
  • JS-数学表达式正则表达式支持(包含希腊字母、小数点等)
    //技术状况规则/**evt:{target:{value:''}},row:{"propName":"""propRule":""}*/functioncheckRule(evt,row,propName,propRule){//匹配a=5,a>5,a<5,a≤6,a≥5等varrule1=/[ΆΈ-ώa-zA-z]+([1-9]......
  • codeforces 573B B. Bear and Blocks(线段树+dp)
    题目链接:codeforces573B题目大意:给出n个连续塔,每个塔有高度hi,每次取走最外层的块,问需要多少次操作能够拿光所有的块。题目分析:首先我们可以知道第一次操作时,对于每个塔的变化满足如下的公式:hi=min(hi−1,hi−1,hi+1)每次操作都满足如下的递推式,我们递推一下得到第k次操作第i......