标签:des style java color os strong
3 1 2 3
7
#include <iostream>
#include <cstdio>
#include <algorithm>
#define MM 1000000007
#define Max 100010
using namespace std;
struct node
{
int l,r,s; //s:子序列的数量
}tree[Max*6];
struct node1
{
int a,b; //a:输入序列的值,b:输入的序列的位置
}sd[Max];
int ss[Max]; //离散化之后的序列
void setit(int l,int r,int d) //建立,这个不用讲了—。—!
{
tree[d].l=l;
tree[d].r=r;
tree[d].s=0;
if(l==r)return;
setit(l,(l+r)/2,d*2);
setit((l+r)/2+1,r,d*2+1);
}
void insert(int e,int k,int d) //插入
{
int l,r,mid;
l=tree[d].l;
r=tree[d].r;
mid=(l+r)/2;
tree[d].s=(tree[d].s+k)%MM; //一路遍历下去的同时在这个区间段[l,r]中加k
if(l==r)return; //遍历到树叶了就结束
if(e>mid)insert(e,k,d*2+1);
else insert(e,k,d*2);
}
int find(int e,int d)
{
int l,r,mid;
l=tree[d].l;
r=tree[d].r;
mid=(l+r)/2;
if(e>=r)return tree[d].s; //如果区间段的右值小于等于e,即确定次区间段类的数字都小于e,就直接返回子序列数
if(e>mid)return (tree[d*2].s+find(e,d*2+1))%MM; //e点在区间段的右端时,左子树的子序列数+继续遍历右子树
else return find(e,d*2);
}
bool cmp(const node1 &a,const node1 &b)
{
return a.a<b.a||a.a==b.a&&a.b<b.b; //这里是重点,标记####,下边会讲
}
int main (void)
{
int n,i,j,k,l,sum;
while(scanf("%d",&n)!=EOF)
{
sum=0;
setit(0,n,1);
for(i=0;i<n;i++)
{
scanf("%d",&sd[i].a);
sd[i].b=i; //标记位置
}
sort(sd,sd+n,cmp); //排序
for(i=0;i<n;i++)
ss[sd[i].b]=i; //把原序列离散成新序列,即把元素弄成1~n,因为元素最大是2^31,数组开不了这么大
for(i=0;i<n;i++)
{
k=(find(ss[i],1)+1)%MM; //查询可以与当前元素形成新序列的子序列的集合,还有元素自己也可以,所以+1
sum=(sum+k)%MM;
insert(ss[i],k,1); //插入,这里把k插入是因为{1}和{1,3}是不同的,都可以用来和4组成新子序列(假设n=4)
}
printf("%d\n",sum);
}
return 0;
}
上边的标记
#### sort排序不能很好地处理相同元素的排序,比如我输入50个1,结果后25个1整整齐齐去了前25个1的前面,这样就破坏了原序列的顺序,我这个离散化是1-n的直接标记,比如1,1,7,7会变为1,2,3,4,而还有一种是压缩性的,会变为1,1,2,2,把相同的也保存相同的,这两个有一个会错,原因就是这里讲的sort的缺陷,所以加一个||a.a==b.a&&a.b<b.b意思是在排序的同时,相同元素不会打乱原先的顺序
HDU--2227--Find the nondecreasing subsequences--线段树,布布扣,bubuko.com
HDU--2227--Find the nondecreasing subsequences--线段树
标签:des style java color os strong
原文地址:http://blog.csdn.net/jingdianitnan/article/details/38019617